装饰者模式
定义:
在不改变原有对象的基础之上,将功能附加到对象上
特点 :
提供了比继承更有弹性的替代方案(扩展语言有对象功能,其实也是建立在继承之上)
类型 :结构型
适用场景
- 扩展一个类的功能或者给一个类添加附加职责
- 动态 的给一个对象添加功能,这些功能可以再动态撤销
优点
- 继承的有力补充,比继承灵活,不改变原有对象的情况下给对象扩展功能。如果需要继承的功能很多,必然会增加很多子类。而且继承需要对继承的功能是可预见的,因为功能在编译的时候就确定了因此是静态的。
而装饰这是应用层代码动态的加载。 - 通过不同的装饰类进行排列组合,可以达到更多的效果。
- 符合开闭原则(换句话说,把类的装饰功能移出去,把类的核心功能和类的装饰功能区分开)
缺点
- 会出现更多的代码,更多的类,增加程序复杂性(其实更多的类是不一定,因为继承也会有很多类,但是比继承多很多对象,因为装饰类比较相似,因此排查错误会比较费劲)
- 动态装饰时,多层装饰时会更复杂
相关设计模式
- 装饰者 和 代理模式
- 装饰者 和 适配器
具体举例
我们创建一个煎饼类
//具体描述
public String getDesc() {
return "煎饼";
}
//获得加个
public int cost() {
return 8;
}
//这时候我们想吃加鸡蛋的煎饼,就创建一个加鸡蛋的类
public class BattercakeWithEgg extends Battercake {
@Override
public String getDesc() {
return super.getDesc() + "加一个鸡蛋";
}
@Override
public int cost() {
return super.cost() + 1;
}
}
//这时候我们想吃加火腿肠的 就再创建一个加火腿肠的类。
public class BattercakeWithEggSausage extends BattercakeWithEgg {
@Override
public String getDesc() {
return super.getDesc() + "加一根香肠";
}
@Override
public int cost() {
return super.cost() + 2;
}
}
煎饼 销售价格:8
煎饼加一个鸡蛋 销售价格:9
煎饼加一个鸡蛋加一根香肠 销售价格:11
test类想像成我们的应用层代码。通过上面的打印结果我们能看出来,我们吃煎饼想要加的东西都实现了。但是如果现在我想吃一张煎饼加两个鸡蛋加两根香肠,那么就没有办法实现了。我们需要创建新的类去继承,但可以看出弊端我们需要无限的创造。可能正是由于这种场景,使得装饰者模式出现。
装饰者模式
装饰者模式是需要有四个东西:一个抽象的实体类、一个确定的实体类、一个抽象的装饰者、一个确定的装饰者。
//抽象的实体
public abstract class ABattercake {
public abstract String getDesc();
public abstract int cost();
}
//具体的实体
public class Battercake extends ABattercake {
@Override
public String getDesc() {
return "煎饼";
}
@Override
public int cost() {
return 8;
}
}
//抽象的的装饰者,当前并不是抽象类。可以变成抽象类,加个抽象方法 比如doSomething()具体需要看业务的实现。比如加鸡蛋需要敲碎壳,加香肠需要撕开包装纸
public class AbstractDecorator extends ABattercake {
private ABattercake aBattercake;
public AbstractDecorator(ABattercake aBattercake) {
this.aBattercake = aBattercake;
}
@Override
public String getDesc() {
return aBattercake.getDesc();
}
@Override
public int cost() {
return aBattercake.cost();
}
}
//鸡蛋装饰
public class EggDecorator extends AbstractDecorator {
public EggDecorator(ABattercake aBattercake) {
super(aBattercake);
}
@Override
public String getDesc() {
return super.getDesc() + "加一个鸡蛋";
}
@Override
public int cost() {
return super.cost() + 1;
}
}
//香肠装饰
public class SausageDecorator extends AbstractDecorator {
public SausageDecorator(ABattercake aBattercake) {
super(aBattercake);
}
@Override
public String getDesc() {
return super.getDesc() + "加一根香肠";
}
@Override
public int cost() {
return super.cost() + 2;
}
}
通过上面的代码我们可以看到,我们把抽象的装饰器和具体的实体都继承了抽象的实体,目的是为了将他们通过共同的父类联系起来。而在抽象装饰者中我们通过构造器,以组合的方式来进行使用。
public AbstractDecorator(ABattercake aBattercake) {
this.aBattercake = aBattercake;
}
我们通过调用抽象的装饰者,其实是把这个行为委托给里面的抽象的实体完成的。
下面是具体的uml
jdk中的装饰者模式
其实要是但看文章基本用不了几分钟,但是吸收、运用、查资料理解我感觉还是要用一定的时间的。书上说不要为了用设计模式而用设计模式,其实我现在感觉就应该为了用设计模式而用设计模式,我认为这样在初期能够更好的去理解。
通过io的uml与之前形成uml,我们可以进行对比着看。inputstream相当于抽象实体类,ByteArrayInputStream、FileInputStream等是具体的实体类,FilterInputStream相当于抽象的装饰者,而且子类则是具体的装饰者。
其中reader,writer也是。但是我还没有验证
假如你还有兴趣去一些源码,还有一些:spring中的TransactionAwareCacheDecorator、SessionRepositoryRrequestWrapper, mybatis中的cache包下decorators的包里面。
共同学习,写下你的评论
评论加载中...
作者其他优质文章