[{"data":1,"prerenderedAt":1040},["ShallowReactive",2],{"i-simple-icons:github":3,"i-simple-icons:x":8,"i-brand:linkedin":10,"i-simple-icons:medium":14,"i-lucide:mail":16,"i-lucide:sun":18,"pattern:\u002Flearn\u002Fdesign-patterns\u002Fdecorator":20,"pattern-group:\u002Flearn\u002Fdesign-patterns\u002Fdecorator":988,"i-lucide:lightbulb":1020,"i-lucide:boxes":1022,"i-lucide:plug":1024,"i-lucide:bridge":1026,"i-lucide:network":1028,"i-lucide:gift":1030,"i-lucide:door-open":1032,"i-lucide:feather":1034,"i-lucide:shield-check":1036,"i-lucide:copy":1038},{"left":4,"top":4,"width":5,"height":5,"rotate":4,"vFlip":6,"hFlip":6,"body":7},0,24,false,"\u003Cpath fill=\"currentColor\" d=\"M12 .297c-6.63 0-12 5.373-12 12c0 5.303 3.438 9.8 8.205 11.385c.6.113.82-.258.82-.577c0-.285-.01-1.04-.015-2.04c-3.338.724-4.042-1.61-4.042-1.61C4.422 18.07 3.633 17.7 3.633 17.7c-1.087-.744.084-.729.084-.729c1.205.084 1.838 1.236 1.838 1.236c1.07 1.835 2.809 1.305 3.495.998c.108-.776.417-1.305.76-1.605c-2.665-.3-5.466-1.332-5.466-5.93c0-1.31.465-2.38 1.235-3.22c-.135-.303-.54-1.523.105-3.176c0 0 1.005-.322 3.3 1.23c.96-.267 1.98-.399 3-.405c1.02.006 2.04.138 3 .405c2.28-1.552 3.285-1.23 3.285-1.23c.645 1.653.24 2.873.12 3.176c.765.84 1.23 1.91 1.23 3.22c0 4.61-2.805 5.625-5.475 5.92c.42.36.81 1.096.81 2.22c0 1.606-.015 2.896-.015 3.286c0 .315.21.69.825.57C20.565 22.092 24 17.592 24 12.297c0-6.627-5.373-12-12-12\"\u002F>",{"left":4,"top":4,"width":5,"height":5,"rotate":4,"vFlip":6,"hFlip":6,"body":9},"\u003Cpath fill=\"currentColor\" d=\"M14.234 10.162L22.977 0h-2.072l-7.591 8.824L7.251 0H.258l9.168 13.343L.258 24H2.33l8.016-9.318L16.749 24h6.993zm-2.837 3.299l-.929-1.329L3.076 1.56h3.182l5.965 8.532l.929 1.329l7.754 11.09h-3.182z\"\u002F>",{"left":4,"top":11,"width":12,"height":12,"rotate":4,"vFlip":6,"hFlip":6,"body":13},32,448,"\u003Cpath fill=\"currentColor\" d=\"M416 32L31.9 32C14.3 32 0 46.5 0 64.3L0 447.7C0 465.5 14.3 480 31.9 480L416 480c17.6 0 32-14.5 32-32.3l0-383.4C448 46.5 433.6 32 416 32zM135.4 416l-66.4 0 0-213.8 66.5 0 0 213.8-.1 0zM102.2 96a38.5 38.5 0 1 1 0 77 38.5 38.5 0 1 1 0-77zM384.3 416l-66.4 0 0-104c0-24.8-.5-56.7-34.5-56.7-34.6 0-39.9 27-39.9 54.9l0 105.8-66.4 0 0-213.8 63.7 0 0 29.2 .9 0c8.9-16.8 30.6-34.5 62.9-34.5 67.2 0 79.7 44.3 79.7 101.9l0 117.2z\"\u002F>",{"left":4,"top":4,"width":5,"height":5,"rotate":4,"vFlip":6,"hFlip":6,"body":15},"\u003Cpath fill=\"currentColor\" d=\"M4.21 0A4.2 4.2 0 0 0 0 4.21v15.58A4.2 4.2 0 0 0 4.21 24h15.58A4.2 4.2 0 0 0 24 19.79v-1.093a5 5 0 0 1-.422.02c-2.577 0-4.027-2.146-4.09-4.832a8 8 0 0 1 .022-.708c.093-1.186.475-2.241 1.105-3.022a3.9 3.9 0 0 1 1.395-1.1c.468-.237 1.127-.367 1.664-.367h.023q.151 0 .303.01V4.211A4.2 4.2 0 0 0 19.79 0Zm.198 5.583h4.165l3.588 8.435l3.59-8.435h3.864v.146l-.019.004c-.705.16-1.063.397-1.063 1.254h-.003l.003 10.274c.06.676.424.885 1.063 1.03l.02.004v.145h-4.923v-.145l.019-.005c.639-.144.994-.353 1.054-1.03V7.267l-4.745 11.15h-.261L6.15 7.569v9.445c0 .857.358 1.094 1.063 1.253l.02.004v.147H4.405v-.147l.019-.004c.705-.16 1.065-.397 1.065-1.253V6.987c0-.857-.358-1.094-1.064-1.254l-.018-.004zm19.25 3.668c-1.086.023-1.733 1.323-1.813 3.124H24V9.298a1.4 1.4 0 0 0-.342-.047m-1.862 3.632c-.1 1.756.86 3.239 2.204 3.634v-3.634z\"\u002F>",{"left":4,"top":4,"width":5,"height":5,"rotate":4,"vFlip":6,"hFlip":6,"body":17},"\u003Cg fill=\"none\" stroke=\"currentColor\" stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\">\u003Cpath d=\"m22 7l-8.991 5.727a2 2 0 0 1-2.009 0L2 7\"\u002F>\u003Crect width=\"20\" height=\"16\" x=\"2\" y=\"4\" rx=\"2\"\u002F>\u003C\u002Fg>",{"left":4,"top":4,"width":5,"height":5,"rotate":4,"vFlip":6,"hFlip":6,"body":19},"\u003Cg fill=\"none\" stroke=\"currentColor\" stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\">\u003Ccircle cx=\"12\" cy=\"12\" r=\"4\"\u002F>\u003Cpath d=\"M12 2v2m0 16v2M4.93 4.93l1.41 1.41m11.32 11.32l1.41 1.41M2 12h2m16 0h2M6.34 17.66l-1.41 1.41M19.07 4.93l-1.41 1.41\"\u002F>\u003C\u002Fg>",{"id":21,"title":22,"body":23,"description":974,"example":975,"extension":976,"group":977,"icon":978,"meta":979,"navigation":250,"order":254,"path":980,"rawbody":981,"seo":982,"sitemap":983,"source":984,"stem":985,"summary":986,"__hash__":987},"patterns\u002Flearn\u002Fdesign-patterns\u002Fdecorator.md","Decorator",{"type":24,"value":25,"toc":964},"minimark",[26,31,35,38,41,45,74,78,83,94,98,121,125,128,189,198,202,269,362,463,611,748,946,952,960],[27,28,30],"h2",{"id":29},"the-idea","The idea",[32,33,34],"p",{},"Say a booking can come with upgrades, and each upgrade changes the price. With subclasses you would need one class for every combination, and the number of classes grows with every new upgrade.",[32,36,37],{},"A decorator wraps an object that has the same interface as itself. When you call a method on the decorator, it calls the same method on the object it wraps and adds its own behaviour before or after. Because the decorator has the same interface, you can wrap a decorator in another decorator, and the client can't tell the difference.",[32,39,40],{},"So instead of a class for every combination, you build combinations at runtime by stacking wrappers: a basic plan, wrapped in a pro upgrade, wrapped in a VIP upgrade.",[27,42,44],{"id":43},"when-to-use-it","When to use it",[46,47,48,52,55,63],"ul",{},[49,50,51],"li",{},"You need to add behaviour to single objects at runtime, not to a whole class.",[49,53,54],{},"Extras can be combined freely, and a subclass for each combination would mean too many classes.",[49,56,57,58,62],{},"You can't or don't want to change the original class, for example because it is ",[59,60,61],"code",{},"final"," or belongs to a library.",[49,64,65,66,69,70,73],{},"You want to add logging, caching or compression around an existing object. Java's ",[59,67,68],{},"BufferedInputStream"," wrapping a ",[59,71,72],{},"FileInputStream"," is a decorator.",[27,75,77],{"id":76},"pros-and-cons","Pros and cons",[79,80,82],"h3",{"id":81},"pros","Pros",[46,84,85,88,91],{},[49,86,87],{},"You add behaviour to objects without changing their class.",[49,89,90],{},"You can combine extras freely, at runtime, by stacking decorators.",[49,92,93],{},"You reuse existing objects: the wrapped object does its normal work, and the decorator only adds to it.",[79,95,97],{"id":96},"cons","Cons",[46,99,100,115,118],{},[49,101,102,103,106,107,110,111,114],{},"Code that relies on the concrete component's type breaks. A ",[59,104,105],{},"ProPlan"," is a ",[59,108,109],{},"Booking",", but it isn't a ",[59,112,113],{},"BasicPlan",".",[49,116,117],{},"Many small wrappers can make the code hard to follow and debug.",[49,119,120],{},"The order of wrapping can matter, and nothing in the types tells you the right order.",[27,122,124],{"id":123},"the-example","The example",[32,126,127],{},"The example prices booking plans. A basic plan costs 10, a pro upgrade adds 10, and a VIP upgrade adds another 10. The demo wraps the basic plan in a pro plan, then wraps that in a VIP plan, and prints the price at each step.",[46,129,130,145,159,166,181],{},[49,131,132,137,138,141,142,114],{},[133,134,135],"strong",{},[59,136,109],{},": the component interface, with ",[59,139,140],{},"getTitle()"," and ",[59,143,144],{},"getPrice()",[49,146,147,152,153,155,156,158],{},[133,148,149],{},[59,150,151],{},"BookingDecorator",": the base decorator. It implements ",[59,154,109],{}," and holds the ",[59,157,109],{}," it wraps.",[49,160,161,165],{},[133,162,163],{},[59,164,113],{},": the concrete component: the plain booking that the others wrap.",[49,167,168,141,172,177,178,180],{},[133,169,170],{},[59,171,105],{},[133,173,174],{},[59,175,176],{},"VipPlan",": concrete decorators. Each ",[59,179,144],{}," asks the wrapped booking for its price and adds 10.",[49,182,183,188],{},[133,184,185],{},[59,186,187],{},"Demo",": builds the stack one layer at a time.",[32,190,191,192,194,195,197],{},"Only ",[59,193,144],{}," builds on the wrapped object. In both decorators, ",[59,196,140],{}," returns a fixed string instead of adding to the wrapped booking's title.",[27,199,201],{"id":200},"the-code","The code",[203,204,210],"pre",{"className":205,"code":206,"filename":207,"language":208,"meta":209,"style":209},"language-java shiki shiki-themes haytham-dark haytham-light","public interface Booking {\n    String getTitle();\n\n    double getPrice();\n}\n","Booking.java","java","",[59,211,212,232,245,252,263],{"__ignoreMap":209},[213,214,217,221,224,228],"span",{"class":215,"line":216},"line",1,[213,218,220],{"class":219},"sVsk0","public",[213,222,223],{"class":219}," interface",[213,225,227],{"class":226},"sNwy7"," Booking",[213,229,231],{"class":230},"sVG6I"," {\n",[213,233,235,238,242],{"class":215,"line":234},2,[213,236,237],{"class":219},"    String",[213,239,241],{"class":240},"sVz7n"," getTitle",[213,243,244],{"class":230},"();\n",[213,246,248],{"class":215,"line":247},3,[213,249,251],{"emptyLinePlaceholder":250},true,"\n",[213,253,255,258,261],{"class":215,"line":254},4,[213,256,257],{"class":219},"    double",[213,259,260],{"class":240}," getPrice",[213,262,244],{"class":230},[213,264,266],{"class":215,"line":265},5,[213,267,268],{"class":230},"}\n",[203,270,273],{"className":205,"code":271,"filename":272,"language":208,"meta":209,"style":209},"public abstract class BookingDecorator implements Booking {\n    protected Booking booking;\n\n    public BookingDecorator(Booking booking) {\n        this.booking = booking;\n    }\n}\n","BookingDecorator.java",[59,274,275,295,309,313,332,351,357],{"__ignoreMap":209},[213,276,277,279,282,285,288,291,293],{"class":215,"line":216},[213,278,220],{"class":219},[213,280,281],{"class":219}," abstract",[213,283,284],{"class":219}," class",[213,286,287],{"class":226}," BookingDecorator",[213,289,290],{"class":219}," implements",[213,292,227],{"class":226},[213,294,231],{"class":230},[213,296,297,300,302,306],{"class":215,"line":234},[213,298,299],{"class":219},"    protected",[213,301,227],{"class":219},[213,303,305],{"class":304},"sWFPS"," booking",[213,307,308],{"class":230},";\n",[213,310,311],{"class":215,"line":247},[213,312,251],{"emptyLinePlaceholder":250},[213,314,315,318,320,323,325,327,330],{"class":215,"line":254},[213,316,317],{"class":219},"    public",[213,319,287],{"class":240},[213,321,322],{"class":230},"(",[213,324,109],{"class":219},[213,326,305],{"class":304},[213,328,329],{"class":230},")",[213,331,231],{"class":230},[213,333,334,338,340,344,347,349],{"class":215,"line":265},[213,335,337],{"class":336},"sheII","        this",[213,339,114],{"class":230},[213,341,343],{"class":342},"s4Awn","booking",[213,345,346],{"class":230}," =",[213,348,305],{"class":304},[213,350,308],{"class":230},[213,352,354],{"class":215,"line":353},6,[213,355,356],{"class":230},"    }\n",[213,358,360],{"class":215,"line":359},7,[213,361,268],{"class":230},[203,363,366],{"className":205,"code":364,"filename":365,"language":208,"meta":209,"style":209},"class BasicPlan implements Booking {\n    @Override\n    public String getTitle() {\n        return \"this Basic plan\";\n    }\n\n    @Override\n    public double getPrice() {\n        return 10;\n    }\n}\n","BasicPlan.java",[59,367,368,382,390,404,415,419,423,429,443,453,458],{"__ignoreMap":209},[213,369,370,373,376,378,380],{"class":215,"line":216},[213,371,372],{"class":219},"class",[213,374,375],{"class":226}," BasicPlan",[213,377,290],{"class":219},[213,379,227],{"class":226},[213,381,231],{"class":230},[213,383,384,387],{"class":215,"line":234},[213,385,386],{"class":230},"    @",[213,388,389],{"class":219},"Override\n",[213,391,392,394,397,399,402],{"class":215,"line":247},[213,393,317],{"class":219},[213,395,396],{"class":219}," String",[213,398,241],{"class":240},[213,400,401],{"class":230},"()",[213,403,231],{"class":230},[213,405,406,409,413],{"class":215,"line":254},[213,407,408],{"class":219},"        return",[213,410,412],{"class":411},"sUOzB"," \"this Basic plan\"",[213,414,308],{"class":230},[213,416,417],{"class":215,"line":265},[213,418,356],{"class":230},[213,420,421],{"class":215,"line":353},[213,422,251],{"emptyLinePlaceholder":250},[213,424,425,427],{"class":215,"line":359},[213,426,386],{"class":230},[213,428,389],{"class":219},[213,430,432,434,437,439,441],{"class":215,"line":431},8,[213,433,317],{"class":219},[213,435,436],{"class":219}," double",[213,438,260],{"class":240},[213,440,401],{"class":230},[213,442,231],{"class":230},[213,444,446,448,451],{"class":215,"line":445},9,[213,447,408],{"class":219},[213,449,450],{"class":336}," 10",[213,452,308],{"class":230},[213,454,456],{"class":215,"line":455},10,[213,457,356],{"class":230},[213,459,461],{"class":215,"line":460},11,[213,462,268],{"class":230},[203,464,467],{"className":205,"code":465,"filename":466,"language":208,"meta":209,"style":209},"public class ProPlan extends BookingDecorator {\n    public ProPlan(Booking booking) {\n        super(booking);\n    }\n\n    @Override\n    public String getTitle() {\n        return \"Pro Plan\";\n    }\n\n    @Override\n    public double getPrice() {\n        return this.booking.getPrice() + 10;\n    }\n}\n","ProPlan.java",[59,468,469,485,501,513,517,521,527,539,548,552,556,562,575,601,606],{"__ignoreMap":209},[213,470,471,473,475,478,481,483],{"class":215,"line":216},[213,472,220],{"class":219},[213,474,284],{"class":219},[213,476,477],{"class":226}," ProPlan",[213,479,480],{"class":219}," extends",[213,482,287],{"class":226},[213,484,231],{"class":230},[213,486,487,489,491,493,495,497,499],{"class":215,"line":234},[213,488,317],{"class":219},[213,490,477],{"class":240},[213,492,322],{"class":230},[213,494,109],{"class":219},[213,496,305],{"class":304},[213,498,329],{"class":230},[213,500,231],{"class":230},[213,502,503,506,508,510],{"class":215,"line":247},[213,504,505],{"class":336},"        super",[213,507,322],{"class":230},[213,509,343],{"class":304},[213,511,512],{"class":230},");\n",[213,514,515],{"class":215,"line":254},[213,516,356],{"class":230},[213,518,519],{"class":215,"line":265},[213,520,251],{"emptyLinePlaceholder":250},[213,522,523,525],{"class":215,"line":353},[213,524,386],{"class":230},[213,526,389],{"class":219},[213,528,529,531,533,535,537],{"class":215,"line":359},[213,530,317],{"class":219},[213,532,396],{"class":219},[213,534,241],{"class":240},[213,536,401],{"class":230},[213,538,231],{"class":230},[213,540,541,543,546],{"class":215,"line":431},[213,542,408],{"class":219},[213,544,545],{"class":411}," \"Pro Plan\"",[213,547,308],{"class":230},[213,549,550],{"class":215,"line":445},[213,551,356],{"class":230},[213,553,554],{"class":215,"line":455},[213,555,251],{"emptyLinePlaceholder":250},[213,557,558,560],{"class":215,"line":460},[213,559,386],{"class":230},[213,561,389],{"class":219},[213,563,565,567,569,571,573],{"class":215,"line":564},12,[213,566,317],{"class":219},[213,568,436],{"class":219},[213,570,260],{"class":240},[213,572,401],{"class":230},[213,574,231],{"class":230},[213,576,578,580,583,585,587,589,592,594,597,599],{"class":215,"line":577},13,[213,579,408],{"class":219},[213,581,582],{"class":336}," this",[213,584,114],{"class":230},[213,586,343],{"class":342},[213,588,114],{"class":230},[213,590,591],{"class":240},"getPrice",[213,593,401],{"class":230},[213,595,596],{"class":230}," +",[213,598,450],{"class":336},[213,600,308],{"class":230},[213,602,604],{"class":215,"line":603},14,[213,605,356],{"class":230},[213,607,609],{"class":215,"line":608},15,[213,610,268],{"class":230},[203,612,615],{"className":205,"code":613,"filename":614,"language":208,"meta":209,"style":209},"public class VipPlan extends BookingDecorator {\n    public VipPlan(Booking booking) {\n        super(booking);\n    }\n\n    @Override\n    public String getTitle() {\n        return \"Pro Plan\";\n    }\n\n    @Override\n    public double getPrice() {\n        return this.booking.getPrice() + 10;\n    }\n}\n","VipPlan.java",[59,616,617,632,648,658,662,666,672,684,692,696,700,706,718,740,744],{"__ignoreMap":209},[213,618,619,621,623,626,628,630],{"class":215,"line":216},[213,620,220],{"class":219},[213,622,284],{"class":219},[213,624,625],{"class":226}," VipPlan",[213,627,480],{"class":219},[213,629,287],{"class":226},[213,631,231],{"class":230},[213,633,634,636,638,640,642,644,646],{"class":215,"line":234},[213,635,317],{"class":219},[213,637,625],{"class":240},[213,639,322],{"class":230},[213,641,109],{"class":219},[213,643,305],{"class":304},[213,645,329],{"class":230},[213,647,231],{"class":230},[213,649,650,652,654,656],{"class":215,"line":247},[213,651,505],{"class":336},[213,653,322],{"class":230},[213,655,343],{"class":304},[213,657,512],{"class":230},[213,659,660],{"class":215,"line":254},[213,661,356],{"class":230},[213,663,664],{"class":215,"line":265},[213,665,251],{"emptyLinePlaceholder":250},[213,667,668,670],{"class":215,"line":353},[213,669,386],{"class":230},[213,671,389],{"class":219},[213,673,674,676,678,680,682],{"class":215,"line":359},[213,675,317],{"class":219},[213,677,396],{"class":219},[213,679,241],{"class":240},[213,681,401],{"class":230},[213,683,231],{"class":230},[213,685,686,688,690],{"class":215,"line":431},[213,687,408],{"class":219},[213,689,545],{"class":411},[213,691,308],{"class":230},[213,693,694],{"class":215,"line":445},[213,695,356],{"class":230},[213,697,698],{"class":215,"line":455},[213,699,251],{"emptyLinePlaceholder":250},[213,701,702,704],{"class":215,"line":460},[213,703,386],{"class":230},[213,705,389],{"class":219},[213,707,708,710,712,714,716],{"class":215,"line":564},[213,709,317],{"class":219},[213,711,436],{"class":219},[213,713,260],{"class":240},[213,715,401],{"class":230},[213,717,231],{"class":230},[213,719,720,722,724,726,728,730,732,734,736,738],{"class":215,"line":577},[213,721,408],{"class":219},[213,723,582],{"class":336},[213,725,114],{"class":230},[213,727,343],{"class":342},[213,729,114],{"class":230},[213,731,591],{"class":240},[213,733,401],{"class":230},[213,735,596],{"class":230},[213,737,450],{"class":336},[213,739,308],{"class":230},[213,741,742],{"class":215,"line":603},[213,743,356],{"class":230},[213,745,746],{"class":215,"line":608},[213,747,268],{"class":230},[203,749,752],{"className":205,"code":750,"filename":751,"language":208,"meta":209,"style":209},"public class Demo {\n    public static void main(String[] args) {\n        \u002F\u002F Basic Plan is 10 ,Pro 20 and Vip 30\n        BasicPlan basicPlan = new BasicPlan();\n        System.out.println(basicPlan.getPrice());\n\n        ProPlan proPlan = new ProPlan(basicPlan);\n        System.out.println(proPlan.getPrice());\n\n        VipPlan vipPlan = new VipPlan(proPlan);\n        System.out.println(vipPlan.getPrice());\n    }\n}\n","Demo.java",[59,753,754,765,793,799,817,844,848,868,891,895,915,938,942],{"__ignoreMap":209},[213,755,756,758,760,763],{"class":215,"line":216},[213,757,220],{"class":219},[213,759,284],{"class":219},[213,761,762],{"class":226}," Demo",[213,764,231],{"class":230},[213,766,767,769,772,775,778,780,783,786,789,791],{"class":215,"line":234},[213,768,317],{"class":219},[213,770,771],{"class":219}," static",[213,773,774],{"class":219}," void",[213,776,777],{"class":240}," main",[213,779,322],{"class":230},[213,781,782],{"class":219},"String",[213,784,785],{"class":230},"[]",[213,787,788],{"class":304}," args",[213,790,329],{"class":230},[213,792,231],{"class":230},[213,794,795],{"class":215,"line":247},[213,796,798],{"class":797},"sFjNZ","        \u002F\u002F Basic Plan is 10 ,Pro 20 and Vip 30\n",[213,800,801,804,807,810,813,815],{"class":215,"line":254},[213,802,803],{"class":219},"        BasicPlan",[213,805,806],{"class":304}," basicPlan ",[213,808,809],{"class":230},"=",[213,811,812],{"class":219}," new",[213,814,375],{"class":240},[213,816,244],{"class":230},[213,818,819,822,824,827,829,832,834,837,839,841],{"class":215,"line":265},[213,820,821],{"class":304},"        System",[213,823,114],{"class":230},[213,825,826],{"class":342},"out",[213,828,114],{"class":230},[213,830,831],{"class":240},"println",[213,833,322],{"class":230},[213,835,836],{"class":304},"basicPlan",[213,838,114],{"class":230},[213,840,591],{"class":240},[213,842,843],{"class":230},"());\n",[213,845,846],{"class":215,"line":353},[213,847,251],{"emptyLinePlaceholder":250},[213,849,850,853,856,858,860,862,864,866],{"class":215,"line":359},[213,851,852],{"class":219},"        ProPlan",[213,854,855],{"class":304}," proPlan ",[213,857,809],{"class":230},[213,859,812],{"class":219},[213,861,477],{"class":240},[213,863,322],{"class":230},[213,865,836],{"class":304},[213,867,512],{"class":230},[213,869,870,872,874,876,878,880,882,885,887,889],{"class":215,"line":431},[213,871,821],{"class":304},[213,873,114],{"class":230},[213,875,826],{"class":342},[213,877,114],{"class":230},[213,879,831],{"class":240},[213,881,322],{"class":230},[213,883,884],{"class":304},"proPlan",[213,886,114],{"class":230},[213,888,591],{"class":240},[213,890,843],{"class":230},[213,892,893],{"class":215,"line":445},[213,894,251],{"emptyLinePlaceholder":250},[213,896,897,900,903,905,907,909,911,913],{"class":215,"line":455},[213,898,899],{"class":219},"        VipPlan",[213,901,902],{"class":304}," vipPlan ",[213,904,809],{"class":230},[213,906,812],{"class":219},[213,908,625],{"class":240},[213,910,322],{"class":230},[213,912,884],{"class":304},[213,914,512],{"class":230},[213,916,917,919,921,923,925,927,929,932,934,936],{"class":215,"line":460},[213,918,821],{"class":304},[213,920,114],{"class":230},[213,922,826],{"class":342},[213,924,114],{"class":230},[213,926,831],{"class":240},[213,928,322],{"class":230},[213,930,931],{"class":304},"vipPlan",[213,933,114],{"class":230},[213,935,591],{"class":240},[213,937,843],{"class":230},[213,939,940],{"class":215,"line":564},[213,941,356],{"class":230},[213,943,944],{"class":215,"line":577},[213,945,268],{"class":230},[32,947,948,949,951],{},"Running ",[59,950,187],{}," prints:",[203,953,958],{"className":954,"code":956,"language":957,"meta":209},[955],"language-text","10.0\n20.0\n30.0\n","text",[59,959,956],{"__ignoreMap":209},[961,962,963],"style",{},"html pre.shiki code .sVsk0, html code.shiki .sVsk0{--shiki-default:#9D9FFE;--shiki-light:#6762D3}html pre.shiki code .sNwy7, html code.shiki .sNwy7{--shiki-default:#D4D7FE;--shiki-light:#3F3B87}html pre.shiki code .sVG6I, html code.shiki .sVG6I{--shiki-default:#85858F;--shiki-light:#71717A}html pre.shiki code .sVz7n, html code.shiki .sVz7n{--shiki-default:#EDEDEF;--shiki-light:#0B0B0C}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html pre.shiki code .sWFPS, html code.shiki .sWFPS{--shiki-default:#C4C4CC;--shiki-light:#3F3F46}html pre.shiki code .sheII, html code.shiki .sheII{--shiki-default:#70ADFF;--shiki-light:#195CAE}html pre.shiki code .s4Awn, html code.shiki .s4Awn{--shiki-default:#C5DDFE;--shiki-light:#534DAF}html pre.shiki code .sUOzB, html code.shiki .sUOzB{--shiki-default:#9EC7FE;--shiki-light:#2873D1}html pre.shiki code .sFjNZ, html code.shiki .sFjNZ{--shiki-default:#6B6B74;--shiki-default-font-style:italic;--shiki-light:#8B8B94;--shiki-light-font-style:italic}",{"title":209,"searchDepth":234,"depth":234,"links":965},[966,967,968,972,973],{"id":29,"depth":234,"text":30},{"id":43,"depth":234,"text":44},{"id":76,"depth":234,"text":77,"children":969},[970,971],{"id":81,"depth":247,"text":82},{"id":96,"depth":247,"text":97},{"id":123,"depth":234,"text":124},{"id":200,"depth":234,"text":201},"The Decorator pattern wraps an object to add behaviour at runtime, so you can stack extras without a subclass for every mix. Explained with a worked Java example of booking plans that add to the price.","Booking plans that add to the price","md","Structural","lucide:gift",{},"\u002Flearn\u002Fdesign-patterns\u002Fdecorator","---\ntitle: Decorator\ngroup: Structural\nicon: lucide:gift\nsummary: 'Wrap an object in another object that adds behaviour, without changing the original class.'\ndescription: 'The Decorator pattern wraps an object to add behaviour at runtime, so you can stack extras without a subclass for every mix. Explained with a worked Java example of booking plans that add to the price.'\nexample: 'Booking plans that add to the price'\norder: 4\nsource: https:\u002F\u002Fgithub.com\u002FHaythamasalama\u002FdesignPattern\u002Ftree\u002Fmaster\u002Fsrc\u002FStructural\u002FDecorator\n---\n\n## The idea\n\nSay a booking can come with upgrades, and each upgrade changes the price. With subclasses you would need one class for every combination, and the number of classes grows with every new upgrade.\n\nA decorator wraps an object that has the same interface as itself. When you call a method on the decorator, it calls the same method on the object it wraps and adds its own behaviour before or after. Because the decorator has the same interface, you can wrap a decorator in another decorator, and the client can't tell the difference.\n\nSo instead of a class for every combination, you build combinations at runtime by stacking wrappers: a basic plan, wrapped in a pro upgrade, wrapped in a VIP upgrade.\n\n## When to use it\n\n- You need to add behaviour to single objects at runtime, not to a whole class.\n- Extras can be combined freely, and a subclass for each combination would mean too many classes.\n- You can't or don't want to change the original class, for example because it is `final` or belongs to a library.\n- You want to add logging, caching or compression around an existing object. Java's `BufferedInputStream` wrapping a `FileInputStream` is a decorator.\n\n## Pros and cons\n\n### Pros\n\n- You add behaviour to objects without changing their class.\n- You can combine extras freely, at runtime, by stacking decorators.\n- You reuse existing objects: the wrapped object does its normal work, and the decorator only adds to it.\n\n### Cons\n\n- Code that relies on the concrete component's type breaks. A `ProPlan` is a `Booking`, but it isn't a `BasicPlan`.\n- Many small wrappers can make the code hard to follow and debug.\n- The order of wrapping can matter, and nothing in the types tells you the right order.\n\n## The example\n\nThe example prices booking plans. A basic plan costs 10, a pro upgrade adds 10, and a VIP upgrade adds another 10. The demo wraps the basic plan in a pro plan, then wraps that in a VIP plan, and prints the price at each step.\n\n- **`Booking`**: the component interface, with `getTitle()` and `getPrice()`.\n- **`BookingDecorator`**: the base decorator. It implements `Booking` and holds the `Booking` it wraps.\n- **`BasicPlan`**: the concrete component: the plain booking that the others wrap.\n- **`ProPlan`** and **`VipPlan`**: concrete decorators. Each `getPrice()` asks the wrapped booking for its price and adds 10.\n- **`Demo`**: builds the stack one layer at a time.\n\nOnly `getPrice()` builds on the wrapped object. In both decorators, `getTitle()` returns a fixed string instead of adding to the wrapped booking's title.\n\n## The code\n\n```java [Booking.java]\npublic interface Booking {\n    String getTitle();\n\n    double getPrice();\n}\n```\n\n```java [BookingDecorator.java]\npublic abstract class BookingDecorator implements Booking {\n    protected Booking booking;\n\n    public BookingDecorator(Booking booking) {\n        this.booking = booking;\n    }\n}\n```\n\n```java [BasicPlan.java]\nclass BasicPlan implements Booking {\n    @Override\n    public String getTitle() {\n        return \"this Basic plan\";\n    }\n\n    @Override\n    public double getPrice() {\n        return 10;\n    }\n}\n```\n\n```java [ProPlan.java]\npublic class ProPlan extends BookingDecorator {\n    public ProPlan(Booking booking) {\n        super(booking);\n    }\n\n    @Override\n    public String getTitle() {\n        return \"Pro Plan\";\n    }\n\n    @Override\n    public double getPrice() {\n        return this.booking.getPrice() + 10;\n    }\n}\n```\n\n```java [VipPlan.java]\npublic class VipPlan extends BookingDecorator {\n    public VipPlan(Booking booking) {\n        super(booking);\n    }\n\n    @Override\n    public String getTitle() {\n        return \"Pro Plan\";\n    }\n\n    @Override\n    public double getPrice() {\n        return this.booking.getPrice() + 10;\n    }\n}\n```\n\n```java [Demo.java]\npublic class Demo {\n    public static void main(String[] args) {\n        \u002F\u002F Basic Plan is 10 ,Pro 20 and Vip 30\n        BasicPlan basicPlan = new BasicPlan();\n        System.out.println(basicPlan.getPrice());\n\n        ProPlan proPlan = new ProPlan(basicPlan);\n        System.out.println(proPlan.getPrice());\n\n        VipPlan vipPlan = new VipPlan(proPlan);\n        System.out.println(vipPlan.getPrice());\n    }\n}\n```\n\nRunning `Demo` prints:\n\n```text\n10.0\n20.0\n30.0\n```\n",{"title":22,"description":974},{"loc":980},"https:\u002F\u002Fgithub.com\u002FHaythamasalama\u002FdesignPattern\u002Ftree\u002Fmaster\u002Fsrc\u002FStructural\u002FDecorator","learn\u002Fdesign-patterns\u002Fdecorator","Wrap an object in another object that adds behaviour, without changing the original class.","A_3QUbb5ZsuFseepgmvd5S_Z89JOvGyxBs-cBDs8HbQ",[989,994,999,1004,1005,1010,1015],{"path":990,"title":991,"icon":992,"summary":993,"order":216},"\u002Flearn\u002Fdesign-patterns\u002Fadapter","Adapter","lucide:plug","A thin wrapper that lets a class work with code that expects a different interface.",{"path":995,"title":996,"icon":997,"summary":998,"order":234},"\u002Flearn\u002Fdesign-patterns\u002Fbridge","Bridge","lucide:bridge","Split a class into two parts that can change on their own: what it does, and how it gets done.",{"path":1000,"title":1001,"icon":1002,"summary":1003,"order":247},"\u002Flearn\u002Fdesign-patterns\u002Fcomposite","Composite","lucide:network","Treat a single object and a group of objects the same way, by building them into a tree.",{"path":980,"title":22,"icon":978,"summary":986,"order":254},{"path":1006,"title":1007,"icon":1008,"summary":1009,"order":265},"\u002Flearn\u002Fdesign-patterns\u002Ffacade","Facade","lucide:door-open","One simple class in front of a complex system, so callers talk to it instead of to every part.",{"path":1011,"title":1012,"icon":1013,"summary":1014,"order":353},"\u002Flearn\u002Fdesign-patterns\u002Fflyweight","Flyweight","lucide:feather","Share the common part of many similar objects, so large numbers of them cost little memory.",{"path":1016,"title":1017,"icon":1018,"summary":1019,"order":359},"\u002Flearn\u002Fdesign-patterns\u002Fproxy","Proxy","lucide:shield-check","A stand-in with the same interface as the real object, which controls when and how the real one is used.",{"left":4,"top":4,"width":5,"height":5,"rotate":4,"vFlip":6,"hFlip":6,"body":1021},"\u003Cpath fill=\"none\" stroke=\"currentColor\" stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M15 14c.2-1 .7-1.7 1.5-2.5c1-.9 1.5-2.2 1.5-3.5A6 6 0 0 0 6 8c0 1 .2 2.2 1.5 3.5c.7.7 1.3 1.5 1.5 2.5m0 4h6m-5 4h4\"\u002F>",{"left":4,"top":4,"width":5,"height":5,"rotate":4,"vFlip":6,"hFlip":6,"body":1023},"\u003Cg fill=\"none\" stroke=\"currentColor\" stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\">\u003Cpath d=\"M2.97 12.92A2 2 0 0 0 2 14.63v3.24a2 2 0 0 0 .97 1.71l3 1.8a2 2 0 0 0 2.06 0L12 19v-5.5l-5-3zM7 16.5l-4.74-2.85M7 16.5l5-3m-5 3v5.17m5-8.17V19l3.97 2.38a2 2 0 0 0 2.06 0l3-1.8a2 2 0 0 0 .97-1.71v-3.24a2 2 0 0 0-.97-1.71L17 10.5zm5 3l-5-3m5 3l4.74-2.85M17 16.5v5.17\"\u002F>\u003Cpath d=\"M7.97 4.42A2 2 0 0 0 7 6.13v4.37l5 3l5-3V6.13a2 2 0 0 0-.97-1.71l-3-1.8a2 2 0 0 0-2.06 0zM12 8L7.26 5.15M12 8l4.74-2.85M12 13.5V8\"\u002F>\u003C\u002Fg>",{"left":4,"top":4,"width":5,"height":5,"rotate":4,"vFlip":6,"hFlip":6,"body":1025},"\u003Cpath fill=\"none\" stroke=\"currentColor\" stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M12 22v-5m3-9V2m2 6a1 1 0 0 1 1 1v4a4 4 0 0 1-4 4h-4a4 4 0 0 1-4-4V9a1 1 0 0 1 1-1zM9 8V2\"\u002F>",{"left":4,"top":4,"width":5,"height":5,"rotate":4,"vFlip":6,"hFlip":6,"body":1027},"\u003Cpath fill=\"none\" stroke=\"currentColor\" stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M10 9.728V16m4-6.272V16m4 4V4m4 7l-4-4A7.5 7.5 0 0 1 6 7l-4 4m20 5H2m4 4V4\"\u002F>",{"left":4,"top":4,"width":5,"height":5,"rotate":4,"vFlip":6,"hFlip":6,"body":1029},"\u003Cg fill=\"none\" stroke=\"currentColor\" stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\">\u003Crect width=\"6\" height=\"6\" x=\"16\" y=\"16\" rx=\"1\"\u002F>\u003Crect width=\"6\" height=\"6\" x=\"2\" y=\"16\" rx=\"1\"\u002F>\u003Crect width=\"6\" height=\"6\" x=\"9\" y=\"2\" rx=\"1\"\u002F>\u003Cpath d=\"M5 16v-3a1 1 0 0 1 1-1h12a1 1 0 0 1 1 1v3m-7-4V8\"\u002F>\u003C\u002Fg>",{"left":4,"top":4,"width":5,"height":5,"rotate":4,"vFlip":6,"hFlip":6,"body":1031},"\u003Cg fill=\"none\" stroke=\"currentColor\" stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\">\u003Cpath d=\"M12 7v14m8-10v8a2 2 0 0 1-2 2H6a2 2 0 0 1-2-2v-8m3.5-4a1 1 0 0 1 0-5A4.8 8 0 0 1 12 7a4.8 8 0 0 1 4.5-5a1 1 0 0 1 0 5\"\u002F>\u003Crect width=\"18\" height=\"4\" x=\"3\" y=\"7\" rx=\"1\"\u002F>\u003C\u002Fg>",{"left":4,"top":4,"width":5,"height":5,"rotate":4,"vFlip":6,"hFlip":6,"body":1033},"\u003Cg fill=\"none\" stroke=\"currentColor\" stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\">\u003Cpath d=\"M10 21H2m8-18H7a2 2 0 0 0-2 2v16m9-9h.01\"\u002F>\u003Cpath d=\"M19 21V5a2 2 0 0 0-1.675-1.974l-6.163-1.013A1 1 0 0 0 10 3v18a1 1 0 0 0 1.124.992zm3 0h-3\"\u002F>\u003C\u002Fg>",{"left":4,"top":4,"width":5,"height":5,"rotate":4,"vFlip":6,"hFlip":6,"body":1035},"\u003Cpath fill=\"none\" stroke=\"currentColor\" stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M14.086 18.412A2 2 0 0 1 12.67 19H5v-7.672a2 2 0 0 1 .586-1.414L11.75 3.75a6 6 0 1 1 8.49 8.49zM16 8L2 22m15.488-7H9\"\u002F>",{"left":4,"top":4,"width":5,"height":5,"rotate":4,"vFlip":6,"hFlip":6,"body":1037},"\u003Cg fill=\"none\" stroke=\"currentColor\" stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\">\u003Cpath d=\"M20 13c0 5-3.5 7.5-7.66 8.95a1 1 0 0 1-.67-.01C7.5 20.5 4 18 4 13V6a1 1 0 0 1 1-1c2 0 4.5-1.2 6.24-2.72a1.17 1.17 0 0 1 1.52 0C14.51 3.81 17 5 19 5a1 1 0 0 1 1 1z\"\u002F>\u003Cpath d=\"m9 12l2 2l4-4\"\u002F>\u003C\u002Fg>",{"left":4,"top":4,"width":5,"height":5,"rotate":4,"vFlip":6,"hFlip":6,"body":1039},"\u003Cg fill=\"none\" stroke=\"currentColor\" stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\">\u003Crect width=\"14\" height=\"14\" x=\"8\" y=\"8\" rx=\"2\" ry=\"2\"\u002F>\u003Cpath d=\"M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2\"\u002F>\u003C\u002Fg>",1793131416615]