这是设计模式系列的第二篇,系列文章目录以下:设计模式
几乎全部的设计模式都是经过增长一层抽象来解决问题。this
上一篇中提到的三个设计模式经过相同的手段来达到相同的目的:它们经过接口和抽象方法来新增抽象层以应对变化。spa
这一系列的后续几篇中会提到的四个设计模式经过相同的手段来达到不一样的目的:它们经过新增一个类并持有原有类的方式实现对其扩展或限制。设计
这一篇先来看看装饰者模式。代理
装饰者模式就好像美颜相机,经过添加不一样的装饰品,它可让你变成另外一个你。(虽然可能面目全非,但本质上仍是你)code
假设有四种饰品:耳环、钻石、黄金、羽毛。不一样装饰品有不一样价格,一般咱们会这样作抽象:
//抽象饰品
public abstract class Accessory {
public abstract String name();//饰品名称
public abstract int cost();//饰品价格
}
//耳环
public class Ring extends Accessory {
@Override
public String name() { return "Ring"; }
@Override
public int cost() { return 20; }
}
//钻石
public class Diamond extends Accessory {
@Override
public String name() { return "Diamond"; }
@Override
public int cost() { return 1000; }
}
//黄金
public class Gold extends Accessory {
@Override
public String name() { return "Gold"; }
@Override
public int cost() { return 300; }
}
//羽毛
public class Feather extends Accessory {
@Override
public String name() { return "Feather"; }
@Override
public int cost() { return 90; }
}
复制代码
现推出两款新饰品:黄金耳环,羽毛黄金耳环。一样的思路,使用继承能够解决问题:
public class GoldRing extends Accessory {
@Override
public String name() { return "GoldRing"; }
@Override
public int cost() { return 320; }
}
public class FeatherGoldRing extends Accessory {
@Override
public String name() { "FeatherGoldRing"; }
@Override
public int cost() { return 1110; }
}
复制代码
GoldRing
和FeatherGoldRing
的价格,若是和黄金相关的饰品有好几十个,那简直是一场噩梦。GoldRing
价格的时候,咱们并无复用现有代码,即没有复用Gold
和Ring
已经定义的cost()
行为,而只是经过继承复用了类型(GoldRing
是一个Accessory
)。只复用类型而没有复用行为的后果是:当Gold
涨价时,GoldRing
无感知。有没有一种比继承更好的方案在现有饰品基础上扩展新的饰品?
采用组合的方式就能够实现既复用类型又复用行为:
public class Gold extends Accessory {
private Accessory accessory;
public Gold(Accessory accessory) { this.accessory = accessory; }
@Override
public String name() {
return "Gold " + accessory.name();
}
@Override
public int cost() {
return 300 + accessory.cost();
}
}
public class Feather extends Accessory {
private Accessory accessory;
public Feather(Accessory accessory) { this.accessory = accessory; }
@Override
public String name() {
return "Feather " + accessory.name();
}
@Override
public int cost() {
return 90 + accessory.cost();
}
}
复制代码
Accessory
,但附加饰品还经过组合的方式持有一个超类型实例,这样就能够经过注入超类型的方式将其和任意基础饰品组合到一块儿造成新的饰品。用组合的方式实现羽毛黄金耳环:
Accessory ring = new Gold(new Feather(new Ring()));
复制代码
Ring
做为基础饰品被Feather
装饰成羽毛耳环,羽毛耳环接着被Gold
装饰成换羽毛黄金耳环。FeatherGoldRing
的子类,而是复用了现有的Feather
和Gold
的行为。这样就解决了子类泛滥和控制力的问题。若是黄金涨价,只须要修改Gold.cost()
,全部被Gold
装饰的饰品价格都会随之而涨。Accessory ring = new Gold(new Gold(new Feather(new Ring())));
复制代码
新的需求来了:基础饰品镶嵌附加饰品收取 10% 的一次性加工费。咱们能够为全部附加饰品增长一层抽象:
public abstract class Decorator extends Accessory{
private Accessory accessory;
public Decorator(Accessory accessory) { this.accessory = accessory; }
@Override
public int cost() {
return 1.1 * accessory.cost();
}
}
复制代码
Decorator
经过组合持有超类型Accessory
且规定了在构造时必须注入超类型,它还定义了镶嵌加工费的收费标准。public class Gold extends Decorator {
public Gold(Accessory accessory){ super(accessory); }
@Override
public String name() {
return "Gold " + accessory.name();
}
@Override
public int cost() {
return 300 + super.cost();
}
}
复制代码
使用装饰者模式后,Gold
和Feather
中有一些样板代码,若是使用Kotlin
能够将代码简化以下:
class Feather(val accessory: Accessory) : Accessory by accessory {
override fun name(): String = "Feather" + accessory.name()
override fun cost(): Int = 90 + accessory.cost()
}
class Gold(val accessory: Accessory) : Accessory by accessory {
override fun name(): String = "Gold" + accessory.name()
override fun cost(): Int = 300 + accessory.cost()
}
复制代码
经过by
关键词把类委托给一个具备超类型的成员变量accessory
,若是不重写,类中的name()
和cost()
的默认实现都将转发给accessory
。
运用组合的设计模式不止装饰者一个,该系列的后续文章会继续分析“组合”在设计模式中的运用。