装饰者模式:ide
动态地将责任附加到对象上。想要扩展功能,装饰者提供有别于继承的另外一种选择。测试
举例:this
不知道你们学校的食堂是什么点餐制度(或者你们就直接想成吃火锅,咱们要火锅料 + 配菜),咱们学校的点餐是:主食大米 + 你想要吃的菜(每一个菜都装在小碗中)。如今问题来了,我点的是大米(0.8元) + 红烧茄子(2.0元) + 荔枝肉(3.5元) + 一个鸡腿(3.5元) + 炒土豆(1.0元),一共10.8元。spa
这只是我想要吃的食品,每一个同窗点餐都不同,因此价格会随着所点食物的不一样而不一样。还有一点就是咱们点餐都要点米饭(这是规定,没有那么多理由,就是这么任性。其实否则,咱们须要有个主对象去修饰),那么咱们应该怎样实现这样的点餐计价方式呢?3d
生活中的实例:code
有一家咖啡店,它提供给咱们以下代码:对象
1 public abstract class Beverage{//饮料抽象类 2 String description = "Unknown Beverage";//饮料名称 3 4 public String getDescription(){//获取饮料名称的方法 5 return description; 6 } 7 8 public abstract double cost();//饮料价格 9 }
这家咖啡店有主饮料(至关于米饭):Espresso(浓缩咖啡1.99$)、HouseBlend(综合咖啡0.89$)、DarkRoast(深焙0.99$)、Decaf(低咖啡因1.05$)四种blog
还有各类配料:Milk(牛奶0.10$)、Mocha(摩卡0.20$)、Soy(豆浆0.15$)、Whip(奶泡0.10$)四种继承
咖啡店想要作出一个点饮料机器,能够点一种主饮料再从四种配料中任意选1到4中配料。该机器能够算出最后的总价,而且能够显示都点了那些东西。接口
分析:
主饮料所有继承自Beverage抽象类,由于店家已经给了Beverage抽象类,咱们只能采用继承方式来实现四种主饮料类,若是没有给建议使用接口方式实现(多用组合,少用继承。)
主饮料咱们只实现其中两种:
1 public class Espresso extends Beverage{//浓缩咖啡类 2 3 public Espresso(){ 4 description = "Espresso"; 5 } 6 7 public double cost(){ 8 return 1.99; 9 } 10 }
1 public class HouseBlend extends Beverage{//综合咖啡类 2 public HouseBlend(){ 3 description = "House Blend Coffee"; 4 } 5 6 public double cost(){ 7 return .89; 8 } 9 }
配料也继承自Beverage,不过咱们在中间加一个桥梁,将主饮料和配料区别对待,这样对于之后的修改有好处:
1 public abstract class CondimentDecorator extends Beverage{//配料接口 2 public abstract String getDescription(); 3 }
全部配料都继承自上面的CondimentDecorator接口:
配料咱们实现其中三种:
1 public class Mocha extends CondimentDecorator {//配料:摩卡类 2 Beverage beverage;//每一个配料中都有一个Beverage对象,该对象存储的是配料修饰的产品。 3 //关键就在这个对象,最后结算的时候,咱们能够调用该对象的getDescription和cost方法 4 //我称它为盒子里面套盒子 5 6 public Mocha(Beverage beverage){ 7 this.beverage = beverage; 8 } 9 10 public String getDescription(){ 11 return beverage.getDescription() + ", Mocha";//调用beverage对象的getDescription()方法 12 } 13 14 public double cost(){ 15 return .20 + beverage.cost();//调用beverage对象的cost()方法 16 } 17 }
1 public class Soy extends CondimentDecorator { 2 Beverage beverage; 3 4 public Soy(Beverage beverage){ 5 this.beverage = beverage; 6 } 7 8 public String getDescription(){ 9 return beverage.getDescription() + ", Soy"; 10 } 11 12 public double cost(){ 13 return .15 + beverage.cost(); 14 } 15 }
1 public class Whip extends CondimentDecorator { 2 Beverage beverage; 3 4 public Whip(Beverage beverage){ 5 this.beverage = beverage; 6 } 7 8 public String getDescription(){ 9 return beverage.getDescription() + ", Whip"; 10 } 11 12 public double cost(){ 13 return .10 + beverage.cost(); 14 } 15 }
测试类:
1 public class StarbuzzCoffee{ 2 3 public static void main(String args[]){ 4 Beverage beverage = new Espresso();//只点主饮料:Espresso 5 System.out.println(beverage.getDescription() + " $" + beverage.cost()); 6 7 Beverage beverage2 = new HouseBlend();//点主饮料:HouseBlend 8 beverage2 = new Mocha(beverage2);//在主饮料中加入Mocha配料:HouseBlend + Mocha 9 beverage2 = new Soy(beverage2);//在饮料中加入Soy配料:HouseBlend + Mocha + Soy 10 beverage2 = new Whip(beverage2);//在饮料中加入Whip配料:HouseBlend + Mocha + Whip 11 System.out.println(beverage2.getDescription() + " $" + beverage2.cost());//结算 12 13 Beverage beverage3 = new Whip( new Soy( new Mocha( new HouseBlend())));//这个和beverage2是同样的只是写法不一样,认真观察 14 System.out.println(beverage3.getDescription() + " $" + beverage3.cost());//结算 15 } 16 }
编译运行结果:
总结:
主饮料和配料都继承自相同的Beverage抽象类,不过为了区分主饮料和配料的不一样,咱们在配料和Beverage抽象类之间有多了一个CondimentDecorator接口。
主饮料实现时,只要getDescription()和cost()方法返回本身的名称和价格就好。配料中则多了一个Beverage对象,getDescription()和cost()方法不只要返回本身的名称和价格,还要将本身修饰的Beverage对象的名称和价格一块儿算上。
在Java中的Java.io类中使用的就是装饰者模式,有兴趣能够本身搜索资料。
思想提炼:
1.对扩展开放,对修改关闭