装饰器设计模式示例
本文是我们名为“ Java设计模式 ”的学院课程的一部分。
在本课程中,您将深入研究大量的设计模式,并了解如何在Java中实现和利用它们。 您将了解模式如此重要的原因,并了解何时以及如何应用模式中的每一个。 在这里查看 !
1.简介
要了解装饰器设计模式,让我们帮助比萨公司制作一个额外的打顶计算器。 用户可以要求向披萨添加额外的配料,而我们的工作是使用该系统添加配料并提高其价格。
这就像在运行时为我们的披萨对象增加了额外的责任,Decorator Design Pattern适用于此类需求。 但是在此之前,让我们进一步了解这种美丽的图案。
2.什么是装饰器设计模式
装饰器设计模式的目的是动态地将附加职责附加到对象上。 装饰器提供了子类别的灵活替代方案,以扩展功能。
装饰器模式用于动态扩展对象的功能,而无需更改原始类的源或使用继承。 这是通过在实际对象周围创建一个称为Decorator
的对象包装来完成的。
Decorator
对象设计为具有与基础对象相同的接口。 这允许客户端对象与Decorator
对象进行交互,其方式与与基础实际对象进行交互的方式完全相同。 Decorator
对象包含对实际对象的引用。 Decorator
对象接收来自客户端的所有请求(调用)。 反过来,它将这些调用转发到基础对象。 Decorator
对象在将请求转发到基础对象之前或之后添加了一些其他功能。 这确保了可以在运行时从外部将附加功能添加到给定对象,而无需修改其结构。
装饰器可防止子类的泛滥,从而减少复杂性和混乱。 添加功能的任意组合都很容易。 相同的功能甚至可以添加两次。 对于给定的对象,可以同时具有不同的装饰器对象。 客户端可以通过将消息发送到适当的装饰器来选择所需的功能。
零件
- 为可以动态添加职责的对象定义接口。
混凝土构件
- 定义可以附加其他职责的对象。
装饰器
- 维护对
Component
对象的引用,并定义一个符合Component接口的接口。
混凝土装饰工
- 向组件添加责任。
3.实施装饰器设计模式
为简单起见,让我们创建一个仅包含两个方法的简单Pizza
接口。
package com.javacodegeeks.patterns.decoratorpattern; public interface Pizza { public String getDesc(); public double getPrice(); }
getDesc
方法用于获取披萨的说明,而getPrice
用于获取价格。
以下是两个具体的Pizza
类:
package com.javacodegeeks.patterns.decoratorpattern; public class SimplyVegPizza implements Pizza{ @Override public String getDesc() { return "SimplyVegPizza (230)"; } @Override public double getPrice() { return 230; } }
package com.javacodegeeks.patterns.decoratorpattern; public class SimplyNonVegPizza implements Pizza{ @Override public String getDesc() { return "SimplyNonVegPizza (350)"; } @Override public double getPrice() { return 350; } }
装饰器包装需要增加功能的对象,因此需要实现相同的接口。 下面是一个抽象装饰器类,它将由所有具体装饰器扩展。
package com.javacodegeeks.patterns.decoratorpattern; public abstract class PizzaDecorator implements Pizza { @Override public String getDesc() { return "Toppings"; } }
以下是具体的装饰器类。
package com.javacodegeeks.patterns.decoratorpattern; public class Broccoli extends PizzaDecorator{ private final Pizza pizza; public Broccoli(Pizza pizza){ this.pizza = pizza; } @Override public String getDesc() { return pizza.getDesc()+", Broccoli (9.25)"; } @Override public double getPrice() { return pizza.getPrice()+9.25; } }
package com.javacodegeeks.patterns.decoratorpattern; public class Cheese extends PizzaDecorator{ private final Pizza pizza; public Cheese(Pizza pizza){ this.pizza = pizza; } @Override public String getDesc() { return pizza.getDesc()+", Cheese (20.72)"; } @Override public double getPrice() { return pizza.getPrice()+20.72; } }
package com.javacodegeeks.patterns.decoratorpattern; public class Chicken extends PizzaDecorator{ private final Pizza pizza; public Chicken(Pizza pizza){ this.pizza = pizza; } @Override public String getDesc() { return pizza.getDesc()+", Chicken (12.75)"; } @Override public double getPrice() { return pizza.getPrice()+12.75; } }
package com.javacodegeeks.patterns.decoratorpattern; public class FetaCheese extends PizzaDecorator{ private final Pizza pizza; public FetaCheese(Pizza pizza){ this.pizza = pizza; } @Override public String getDesc() { return pizza.getDesc()+", Feta Cheese (25.88)"; } @Override public double getPrice() { return pizza.getPrice()+25.88; } }
package com.javacodegeeks.patterns.decoratorpattern; public class GreenOlives extends PizzaDecorator{ private final Pizza pizza; public GreenOlives(Pizza pizza){ this.pizza = pizza; } @Override public String getDesc() { return pizza.getDesc()+", Green Olives (5.47)"; } @Override public double getPrice() { return pizza.getPrice()+5.47; } }
package com.javacodegeeks.patterns.decoratorpattern; public class Ham extends PizzaDecorator{ private final Pizza pizza; public Ham(Pizza pizza){ this.pizza = pizza; } @Override public String getDesc() { return pizza.getDesc()+", Ham (18.12)"; } @Override public double getPrice() { return pizza.getPrice()+18.12; } }
package com.javacodegeeks.patterns.decoratorpattern; public class Meat extends PizzaDecorator{ private final Pizza pizza; public Meat(Pizza pizza){ this.pizza = pizza; } @Override public String getDesc() { return pizza.getDesc()+", Meat (14.25)"; } @Override public double getPrice() { return pizza.getPrice()+14.25; } }
package com.javacodegeeks.patterns.decoratorpattern; public class RedOnions extends PizzaDecorator{ private final Pizza pizza; public RedOnions(Pizza pizza){ this.pizza = pizza; } @Override public String getDesc() { return pizza.getDesc()+", Red Onions (3.75)"; } @Override public double getPrice() { return pizza.getPrice()+3.75; } }
package com.javacodegeeks.patterns.decoratorpattern; public class RomaTomatoes extends PizzaDecorator{ private final Pizza pizza; public RomaTomatoes(Pizza pizza){ this.pizza = pizza; } @Override public String getDesc() { return pizza.getDesc()+", Roma Tomatoes (5.20)"; } @Override public double getPrice() { return pizza.getPrice()+5.20; } }
package com.javacodegeeks.patterns.decoratorpattern; public class Spinach extends PizzaDecorator{ private final Pizza pizza; public Spinach(Pizza pizza){ this.pizza = pizza; } @Override public String getDesc() { return pizza.getDesc()+", Spinach (7.92)"; } @Override public double getPrice() { return pizza.getPrice()+7.92; } }
我们需要用这些浇头装饰披萨对象。 上面的类包含对需要装饰的披萨对象的引用。 装饰器对象在调用装饰器的函数后将其功能添加到装饰器。
package com.javacodegeeks.patterns.decoratorpattern; import java.text.DecimalFormat; public class TestDecoratorPattern { public static void main(String[] args) { DecimalFormat dformat = new DecimalFormat("#.##"); Pizza pizza = new SimplyVegPizza(); pizza = new RomaTomatoes(pizza); pizza = new GreenOlives(pizza); pizza = new Spinach(pizza); System.out.println("Desc: "+pizza.getDesc()); System.out.println("Price: "+dformat.format(pizza.getPrice())); pizza = new SimplyNonVegPizza(); pizza = new Meat(pizza); pizza = new Cheese(pizza); pizza = new Cheese(pizza); pizza = new Ham(pizza); System.out.println("Desc: "+pizza.getDesc()); System.out.println("Price: "+dformat.format(pizza.getPrice())); } }
上面的代码将产生以下输出:
Desc: SimplyVegPizza (230), Roma Tomatoes (5.20), Green Olives (5.47), Spinach (7.92) Price: 248.59 Desc: SimplyNonVegPizza (350), Meat (14.25), Cheese (20.72), Cheese (20.72), Ham (18.12) Price: 423.81
在上面的类中,我们首先创建了SimplyVegPizza
,然后用RomaTomatoes
, GreenOlives
和Spinach
装饰它。 输出中的desc
显示添加在SimplyVegPizza
中的浇头,且价格为所有价格的总和。
我们对SimplyNonVegPizza
做了同样的事情,并在SimplyNonVegPizza
添加了不同的SimplyNonVegPizza
。 请注意,您可以为一个对象多次装饰同一件事。 在上面的示例中,我们两次添加了cheese
; 它的价格也增加了两倍,可以在输出中看到。
当您需要在运行时为对象添加额外功能并对其进行修改时,Decorator设计模式看起来不错。 但这会导致很多小物体。 使用Decorator的设计通常会导致系统由许多看起来相似的小对象组成。 对象的区别仅在于它们的互连方式不同,不在于它们的类或变量的值。 尽管这些系统很容易被理解它们的人定制,但是它们可能很难学习和调试。
4.何时使用装饰设计模式
在以下情况下,请使用Decorator模式:
- 动态透明地向单个对象添加职责,即不影响其他对象。
- 对于可以撤消的责任。
- 当通过子类扩展不可行时。 有时可能会有大量独立的扩展,并且会产生大量的子类来支持每种组合。 或者,类定义可能被隐藏或无法用于子类化。
5. Java中的装饰器设计模式
-
java.io.BufferedInputStream(InputStream)
-
java.io.DataInputStream(InputStream)
-
java.io.BufferedOutputStream(OutputStream)
-
java.util.zip.ZipOutputStream(OutputStream)
-
java.util.Collections#checked[List|Map|Set|SortedSet|SortedMap]()
6.下载源代码
这是关于装饰设计模式的课程。
您可以在此处下载相关的源代码: DecoratorPattern-Project
翻译自: https://www.javacodegeeks.com/2015/09/decorator-design-pattern.html