人物:大鸟,小菜
事件:小菜要去约会,不知道穿什么,怎么搭配,大鸟借着搭配衣服这件事,给小菜讲了装饰模式
装饰模式:
1.大鸟让小菜通过代码实现装扮,大鸟指出了小菜的不足
2.在结合了开放封闭原则后,小菜进行了第二次装扮,大鸟依然指出了小菜的正确和失误,引出了装饰模式
3.小菜在领悟了装饰模式后,进行了第三次装扮
4.最后对装扮模式进行了小结
小菜的第一次装扮
@Slf4j public class Person { private String name; public Person(String name) { this.name = name; } public void wearTShirts() { log.info("大T恤"); }、 public void wearBigTrouser() { log.info("垮裤"); } public void wearSneakers() { log.info("破球鞋"); } public void wearSuit() { log.info("穿西装"); } public void wearTie() { log.info("领带"); } public void wearLeatherShoes() { log.info("皮鞋"); } public void show() { log.info("装扮的:{}", name); } }
客户端:
@Slf4j public class PersonWear { public static void main(String[] args) { Person xc = new Person("小菜"); log.info("第一种装扮:"); xc.wearSuit(); xc.wearTie(); xc.wearLeatherShoes(); xc.show(); } }
大鸟:现在需要增加超人的装扮,需要怎么改呢?
小菜的第二次装扮
在学习了开放-封闭原则后,小菜出了第二次装扮
Person类:
@Slf4j public class Person { private String name; public Person(String name) { this.name = name; } public void show() { log.info("装扮的:{}", name); } }
服饰抽象类:
public abstract class Finery { public abstract void show(); }
各种服饰子类:
@Slf4j public class TShirts extends Finery { @Override public void show() { log.info("大T恤"); } }
@Slf4j public class BigTrouser extends Finery { @Override public void show() { log.info("垮裤"); } }
@Slf4j public class Sneakers extends Finery { @Override public void show() { log.info("破球鞋"); } }
......
客户端代码:
@Slf4j public class PersonWear { public static void main(String[] args) { Person xc = new Person("小菜"); log.info("第一种装扮:"); Finery dtx = new TShirts(); Finery kk = new BigTrouser(); Finery pqx = new Sneakers(); dtx.show(); kk.show(); pqx.show(); xc.show(); } }
小菜:这下结果和之前的一样,而且面向了对象,只要有新的服饰,再增减子类即可
大鸟:但是这段代码还是有点问题:
dtx.show();
kk.show();
pqx.show();
xc.show();
这里显式地放在了外面,这就好比当着大家的面在穿衣服,其实应该在内部组装,我们要把所需的功能按正确的顺序串联起来进行控制,于是这里就引入了新的模式--装饰模式
装饰模式
装饰模式:动态地给一个对象添加一些额外的职责,就增加功能来说,装饰模式比生成子类更加灵活。
它的实现:
Component类,这是最原始的对象,是一个对象接口,可以给对象动态添加职责
public abstract class Component { public abstract void Operation(); }
ConcreteComponent类,定义一个具体的对象,是最基本接口的实现,我们要装饰它
@Slf4j public class ConcreteComponent extends Component { @Override public void Operation() { log.info("具体对象的操作"); } }
Decorator类,装饰抽象类,继承了Component,从外类扩展Component功能
public class Decorator extends Component { protected Component component; public void setComponent(Component component) { this.component = component; } @Override public void Operation() { if (component != null) { component.Operation(); } } }
ConcerteDecoratorA类和ConcerteDecoratorB类,先执行Operation()方法,再执行addedState赋值或addedBehavior方法调用,相当于进行了装饰
@Slf4j public class ConcerteDecoratorA extends Decorator { private String addedState; @Override public void Operation(){ this.Operation(); addedState = "New State"; log.info("具体装饰对象A的操作"); } }
@Slf4j public class ConcreteDecoratorB extends Decorator { @Override public void Operation() { this.Operation(); AddedBehavior(); log.info("具体装饰对象B的操作"); } private void AddedBehavior() { //本类独有的方法,以作区别 } }
客户端代码,先实例化对象c,再用ConcerteDecoratorA的实例化对象d1来包装c,再用ConcreteDecoratorB实例话的对象d2包装d1,最终再执行d2的Operation()
public static void main(String[] args) { ConcreteComponent c = new ConcreteComponent(); ConcreteDecoratorA d1 = new ConcreteDecoratorA(); ConcreteDecoratorB d2 = new ConcreteDecoratorB(); d1.setComponent(c); d2.setComponent(d1); d2.Operation(); }
小菜:原来装饰模式是利用setComponent来对对象进行包装,这样每个装饰对象的实现就和如何使用这个对象分开了,每个装饰对象只用关心自己的功能
大鸟:那我们刚刚用的Person()类,是属于Component类还是ConcreteComponent类呢?
小菜:我觉得如果只有ConcreteComponent类而没有抽象的Component类,那么Decorator类可以是ConcreteComponent的一个子类,同理,如果没有ConcreteDecoratorA和ConcreteDecoratorB,而是只有一个ConcreteDecorator类,那么ConcreteDecorator类和Decorator类也可以合二为一,这里我们就不必用Component类,直接让服饰类Decorator类继承人类ConcreteComponent即可。
小菜的第三次装扮
Person类(ConcreteComponent类)
@Slf4j
public class Person {
public Person() {}
private String name;
public Person(String name) {
this.name = name;
}
public void show() {
log.info("装扮的:{}", name);
}
}
服饰类(Decorator)
public class Finery extends Person {
protected Person component;
public void Decorate(Person component) {
this.component = component;
}
@Override
public void show() {
if (component != null) {
component.show();
}
}
}
具体服饰类:
@Slf4j public class TShirts extends Finery { @Override public void show() {
super.show(); log.info("大T恤"); } } @Slf4j public class Sneakers extends Finery { @Override public void show() {
super.show(); log.info("破球鞋"); } } @Slf4j public class BigTrouser extends Finery { @Override public void show() {
super.show(); log.info("垮裤"); } }
小结
1.装饰模式:
装饰模式是为已有功能动态地添加更多功能的一种方式
2.什么时候用装饰模式?
在最初设计系统时,当系统需要新的功能,就要向旧的类中添加新的代码,这些新加的代码通常装饰了原有类的核心职责和主要行为,它们在主类添加了新的字段,新的逻辑,增加了主类的复杂度,而新加入的东西可能只是为了满足某个特殊的需求。而装饰模式把要装饰的功能放在单独的类中,并让这个类包装它所要装饰的对象,因此要执行特殊行为时,客户代码就可以在运行时有选择地,按顺序地使用装饰功能包装对象了
3.优点:
(1)把类中的装饰功能从类中搬移去除,这样可以简化原有的类
(2)有效地把类的核心职责和装饰功能区分开了,而且可以去除相关类中重复的装饰逻辑