前言
今天学习装饰模式,这个模式在Android源码中很常见,记录一下相关知识,方便自己后续查阅和回顾。
demo根据参考文中写的。
正文
装饰模式
通过使用装饰器模式,可以在不修改现有代码的基础上扩展对象的功能,
优缺点
优点
采用装饰模式扩展对象的功能比采用继承方式更加灵活
可以设计出多个不同的具体装饰类,创造出多个不同行为的组合
缺点
装饰模式增加了许多子类,如果过度使用会使程序变得很复杂
错误示范
不使用装饰者,扩展一个类的功能会使用继承方式来实现。
下面以煎饼果子为例
煎饼果子 (什么都不加的)
鸡蛋+煎饼果子
生菜+煎饼果子
生菜+鸡蛋+煎饼果子
/** * 煎饼果子 */ public class Pancakes { public String name(){ return "煎饼"; } public double price(){ return 4.0f; } }
/** * 鸡蛋+煎饼果子 */ public class EggPancakes extends Pancakes { public String name() { return "鸡蛋+" + super.name(); } public double price() { return 4.0f + 1.0f; } }
/** * 生菜+煎饼果子 */ public class LettucePancakes extends Pancakes { public String name() { return "生菜+" + super.name(); } public double price() { return super.price(); } }
/** * 生菜+鸡蛋+煎饼果子 */ public class LettuceEggPancakes extends EggPancakes{ public String name() { return "生菜+" + super.name(); } public double price() { return super.price(); } }
如果要新增一个火腿肠选项呢?
比如,火腿肠,生菜火腿肠,鸡蛋火腿肠,鸡蛋生菜火腿肠,按照上面岂不是要新增4个类。
通过继承,需要创建多个类,而且还耦合度高,再新增一个鸡柳,类还会更多更复杂。
因此,需要使用装饰者模式。
主要角色
下面是装饰者主要角色
抽象构件(Component):
定义一个抽象接口以规范准备接收附加责任的对象。
具体构件(Concrete Component):
实现抽象构件,通过装饰角色为其添加一些职责。
抽象装饰(Decorator):
继承抽象构件,并包含具体构件的实例,可以通过其子类扩展具体构件的功能。
具体装饰(ConcreteDecorator):
实现抽象装饰的相关方法,并给具体构件对象添加附加的责任。
demo
还是以煎饼果子为例,可以加鸡蛋,生菜,甚至还可以加火腿肠。
对比上面[错误示范]看看有啥区别。
抽象构件
抽象构件(Component),定义一个抽象接口以规范准备接收附加责任的对象。
定义一个饼,有名字和价钱两个抽象接口。
public abstract class Cakes { public abstract String name(); public abstract double price(); }
具体构件
具体构件(Concrete Component),实现抽象构件,通过装饰角色为其添加一些职责。
也是需要装饰的对象,这里为煎饼果子,原汁原味的饼。
public class Pancakes extends Cakes { @Override public String name() { return "煎饼果子"; } @Override public double price() { return 4.0f; } }
每个人口味不一样,有人需要生菜,也有人需要鸡蛋,当然也有人两个多要(反正生菜免费)。
抽象装饰
继承抽象构件,并包含具体构件的实例,可以通过其子类扩展具体构件的功能。
public abstract class Decorator extends Cakes{ Cakes cakes; }
为抽象类,我们直接用父类Cakes的抽象类。
当然可以新增一些让子类实现的抽象方法,我们这里为了简单省略了。
具体装饰
实现抽象装饰的相关方法,并给具体构件对象添加附加的责任。
鸡蛋装饰的煎饼果子
/** * 鸡蛋+煎饼果子 */ public class EggPancakes extends Decorator { public EggPancakes(Cakes cakes) { this.cakes = cakes; } @Override public String name() { return "鸡蛋+" + cakes.name(); } @Override public double price() { return 1.0f + cakes.price(); } }
生菜装饰的煎饼果子
/** * 生菜+煎饼果子 */ public class LettucePanCakes extends Decorator { public LettucePanCakes(Cakes cakes) { this.cakes = cakes; } @Override public String name() { return "生菜+" + cakes.name(); } @Override public double price() { return cakes.price(); } }
火腿装饰的煎饼果子
/** * 火腿肠+ 煎饼果子 */ public class HamPanCakes extends Decorator { public HamPanCakes(Cakes cakes) { this.cakes = cakes; } @Override public String name() { return "火腿肠+" + cakes.name(); } @Override public double price() { return cakes.price()+ 2.0f; } }
客户端
//煎饼果子 Pancakes pancakes = new Pancakes(); //鸡蛋+煎饼果子 EggPancakes eggPancakes = new EggPancakes(pancakes); //生菜+鸡蛋+煎饼果子 LettucePanCakes lettuceEggPanCakes = new LettucePanCakes(eggPancakes); //生菜+鸡蛋+火腿肠+煎饼果子 HamPanCakes hamLettuceEggPanCakes = new HamPanCakes(lettuceEggPanCakes);
打印结果
煎饼果子 --> 4.0 鸡蛋+煎饼果子 --> 5.0 生菜+鸡蛋+煎饼果子 --> 5.0 火腿肠+生菜+鸡蛋+煎饼果子 --> 7.0
相对[错误示范]的代码,使用装饰模式后类更少了,也更明了。
参考文章
《》
《》
《》
《