装饰器模式
-
解释:在不改变原有对象的基础上,将功能附加到对象上(提供了比继承更有弹性的替代方案,属于结构性),符合开闭原则,追加而不修改。装饰器模式本身就是一个打扮的过程,面包和奶油的关系。比如用奶油、巧克力将面包打扮成蛋糕。
-
示意图
啤酒分为百威、青岛、燕京等品牌,在啤酒的基础上增加了品牌和价钱。现在用代码的形式来体现。-
代码实现
-
Drink
package decorate; //饮品的抽象 public interface Drink { //价格 public double price(); //代表当前饮品的名字 public String name(); }
-
Beer
package decorate; //具体被装饰的饮品 啤酒 public class Beer implements Drink { @Override public double price() { return 2.0; } @Override public String name() { return "啤酒"; } }
-
Decorator
package decorate; public class Decorator implements Drink { Drink drink; public Decorator(Drink drink){ this.drink =drink; } @Override public double price() { return drink.price(); } @Override public String name() { return drink.name(); } }
-
QingDaoDecorator
package decorate; public class QingDaoDecorator extends Decorator { public QingDaoDecorator(Drink drink) { super(drink); } @Override public double price() { return drink.price()+4; } @Override public String name() { return "青岛"+drink.name(); } }
-
Test
package decorate; public class Test { public static void main(String[] args) { Drink b = new Beer(); Drink beer = new QingDaoDecorator(b); System.out.println(beer.name()+" "+beer.price()); } }
-
运行结果
青岛啤酒 6.0
-
进一步说明
-
假如装饰器中,有需要具体装饰者实现的类,那么可以用抽象类,需要根据具体业务需求。
package decorate; public abstract class Decorator implements Drink { Drink drink; public Decorator(Drink drink){ this.drink =drink; } public abstract void method(); @Override public double price() { return drink.price(); } @Override public String name() { return drink.name(); } }
-
现在增加燕京啤酒
-
QingDaoDecorator
package decorate; public class YanQingDecorator extends Decorator { public YanQingDecorator(Drink drink) { super(drink); } @Override public double price() { return drink.price()+3; } @Override public String name() { return "燕京"+drink.name(); } }
-
Test
package decorate; public class Test { public static void main(String[] args) { Drink b = new Beer(); Drink beer = new QingDaoDecorator(b); System.out.println(beer.name()+" "+beer.price()); Drink beer2 = new YanQingDecorator(b); System.out.println(beer2.name()+" "+beer2.price()); } }
-
运行结果
青岛啤酒 6.0 燕京啤酒 5.0
-
-
-
-
还可以在饮品下增加可乐。
-
Cola
package decorate; public class Cola implements Drink { @Override public double price() { return 2.5; } @Override public String name() { return "可乐"; } }
-
QingDaoDecorator
package decorate; public class QingDaoDecorator extends Decorator { public QingDaoDecorator(Drink drink) { super(drink); } @Override public double price() { return drink.price()+4; } @Override public String name() { return "青岛"+drink.name(); } }
-
Test
package decorate; public class Test { public static void main(String[] args) { Drink b = new Beer(); Drink beer = new QingDaoDecorator(b); System.out.println(beer.name()+" "+beer.price()); Drink beer2 = new YanQingDecorator(b); System.out.println(beer2.name()+" "+beer2.price()); Drink cola = new Cola(); Drink coladrink = new BaiShiColaDecorator(cola); System.out.println(coladrink.name()+" "+coladrink.price()); } }
-
运行结果
青岛啤酒 6.0 燕京啤酒 5.0 百事可乐 2.5
-
-
-
关键点:
- 被修饰对象基类:定义对象的接口,可以给这些对象动态添加职责。
- 具体被修饰对象:定义具体的对象,装饰器可以给它添加额外而职责。
- 修饰者抽象类:实现基类对象的接口,传入具体被修饰修饰的对象。
- 具体修饰者:在内部对被修饰的对象进行扩展。实现扩展而不修改的目标。
-
优点和缺点
- 优点:装饰者和被装饰者可以独立发展,互补耦合,装饰模式是继承模式的替代者,可动态扩展一个类的功能。符合开闭原则。
- 缺点:多层装饰比较复杂,就是可读性的意思。
-
练习
- 土豆饼做成番茄味
- 基类接口:饼 cake
- 土豆饼:被修饰具体类
- 抽象装饰器
- 具体装饰器
- 土豆饼做成番茄味