这是我参与更文挑战的第30天,活动详情查看:更文挑战
什么是装饰器模式(Decorator )
概念
装饰器模式(Decorator Pattern)属于结构型模式,是在不改变现有的对象结构(代码)的情况下,对这个对象动态添加一些新的职责(功能),希望通过用组合对象的方式替代继承的方式来实现对类的扩展。
我们看它的名字就知道,装饰器,像我们带的手表,就能够不影响我们,然后赋予我们看时间的能力。
装饰器模式是在不改变核心功能的基础上去新增一些新的功能,和代理模式非常地相似,在下面学习完如何实现装饰器模式后会做一下区分的总结。
优点
- 装饰器模式是继承的一种替代方式,通过组合的方式完成继承的功能,但却避免了继承的侵入性。
- 降低类间的耦合。被装饰类和装饰类都可以独立发展,不会相互影响。
- 符合开放封闭原则。
缺点
过度使用装饰器模式会导致类的数量变得庞大,也会增加程序的复杂度。
设计模式虽好,不要贪杯哦。
原则
“+”代表遵守,“-”代表不遵守或者不相关
原则 | 开放封闭 | 单一职责 | 迪米特 | 里氏替换 | 依赖倒置 | 接口隔离 | 合成复用 |
---|---|---|---|---|---|---|---|
+ | + | + | – | + | + | + | |
适用场景(动机)
- 想要避免使用继承来扩展功能。
- 实现的子类有不同的维度。
如何实现
想要实现装饰器模式,需要有以下四样东西:
- 抽象构件接口:定义具体构件类的接口。
- 具体构件类(被装饰类):实现抽象构件接口,创建要给被修饰类。
- 装饰抽象类:实现抽象构件,规定实现类要实现的方法,并组合具体构建类的对象。
- 具体装饰类:继承装饰抽象类,实现方法。
上类图
上代码
抽象构件接口:Component
/**
*
* 抽象构件接口
* 模拟人类
* Created on 2021/6/2.
*
* @author xuxiaobai
*/
public interface Component {
void say();
void eat();
}
复制代码
具体构件类:ConcreteComponent
/**
* 具体构件类
* 例如,翠花类
* Created on 2021/6/2.
*
* @author xuxiaobai
*/
public class ConcreteComponent implements Component{
@Override
public void say() {
System.out.println("你好,我叫翠花。");
}
@Override
public void eat() {
System.out.println("真好吃!");
}
}
复制代码
装饰抽象类:Decorator
/**
* 装饰抽象类
* Created on 2021/6/2.
*
* @author xuxiaobai
*/
public abstract class Decorator implements Component{
Component component=new ConcreteComponent();
@Override
public void say() {
component.say();
}
@Override
public void eat() {
component.eat();
}
/**
* 看时间
*/
public abstract void lookTime();
}
复制代码
具体装饰类:ConcreteDecorator
/**
* 具体装饰类
* 带上手表的翠花类
* Created on 2021/6/2.
*
* @author xuxiaobai
*/
public class ConcreteDecorator extends Decorator{
@Override
public void lookTime() {
System.out.println("我看到我的小米手环显示,现在是09:30");
}
}
复制代码
测试:
/**
* Created on 2021/6/2.
*
* @author xuxiaobai
*/
public class DecoratorTest {
public static void main(String[] args) {
/**
* 没有手表的翠花类
*/
Component component = new ConcreteComponent();
component.say();
component.eat();
/**
* 有手表的翠花类
*/
Decorator decorator = new ConcreteDecorator();
decorator.say();
decorator.eat();
decorator.lookTime();
/**
* 结果:
* 你好,我叫翠花。
* 真好吃!
* 你好,我叫翠花。
* 真好吃!
* 我看到我的小米手环显示,现在是09:30
*/
}
}
复制代码
这里的翠花想戴手表就戴(Decorator),不想戴就不戴(ConcreteComponent),非常地灵活。
总结
跟代理模式的区别:
装饰器模式跟静态代理非常地相似,代理模式也有采用静态代理的方式去实现代理的,两者之间有什么区别呢?
有的,装饰器模式的重点在于扩展新的方法,像上面的例子,翠花除了说话和吃,还扩展了看时间的方法;而代理模式则是为每个原有方法附加新的功能,例如翠花想打包KFC回家吃,可以自己去店里点,也可以在KFC小程序上点,相当于由小程序帮你转告店员你要点餐,做的事情跟自己去店里点做的事情是一样的,只是现在不需要自己去店里了。
我个人认为,虽然装饰器模式是继承的一种替代,但在想要新扩展的类数量不是很多时,可以考虑直接使用继承的方式来扩展,等扩展类的数量稍微有点多了,再对这一堆类进行一个重构,重构成装饰器模式。
——————————————————————————————
你知道的越多,不知道的就越多。
如果本文章内容有问题,请直接评论或者私信我。如果觉得我写得还不错的话,点个赞也是对我的支持哦
未经允许,不得转载!