装饰者模式可以给已经存在的对象基础上动态的增强,也就是在不改变之前源码的基础上进行增强。
满足开闭原则。
开闭原则顾名思义就是:对扩展开放,对修改关闭。我们在想要扩展功能的时候,不能通过修改源码的方式,而必须通过扩展的方式。
装饰者模式实现
通过一个简单的例子来说明什么是装饰者模式。
我们目前有一个Person类,他有一个吃饭的功能,但是在之前的代码之后,技术经理非要让我们添加功能,比如想在吃饭之前河口啤酒,这可如何是好呀?难道去修改源码?
那显然不行,首先为了尽量让我们的代码互相兼容(代码功能都变了,显然不兼容),另外一个就是要满足开闭原则(使用扩展的方式来增加功能)。这可以通过装饰者模式来实现。
下边看具体代码实现:
我们定义一个接口实现人的吃饭功能:
之后定义一个被装饰的子类对象:
这样就能实现一个人吃麻辣香锅的功能了。测试如下:
执行结果:
但是如果我们想改变之前的逻辑,一个人在吃饭的时候还要喝啤酒呢?
如何更加优雅的在不改变源码的基础上修改之前的功能呢?
这就要用到今天所讲的装饰者模式了,我们可以定义一个装饰者类,对原来的对象进行装饰,然后调用这个装饰者对象就可以了。
定义的装饰者如下:
/**
* @author xxy
* @date 2020/7/20
* 对Person的子类进行装饰
*/
public class ManDecorator implements Person {
private Person person;
ManDecorator(Person person) {
this.person = person;
}
@Override
public void eat() {
System.out.println("吃饭之前喝点啤酒...");
person.eat();
}
}
然后我们在调用装饰者对象帮我们完成功能就可以了,测试类如下:
/**
* @author xxy
* @date 2020/7/20
* 测试类
*/
public class Test {
public static void main(String[] args) {
Person man = new Man();
//man.eat();
Person manDecorator = new ManDecorator(man);//装饰者对象
manDecorator.eat();
}
}
这样就能在不修改源码的基础上对之前的方法进行增强了。
此时如果想要对原来的方法增加其他的功能,同样也可以编写其他的装饰对象,每次都调用这个装饰者对象就可以了。比如:吃饭前洗手,吃饭后打扫卫生等等。
细节
这里要注意一个细节,就是我们的装饰者也要实现被装饰对象所实现的接口,这样就能使用多态的方式面向接口编程,在被装饰之后依旧返回一个接口引用,使其他类感知不到我们装饰者的存在。
比如我们上边的如果不使用装饰对象,那么会返回一个Person接口的引用,正因为我们的装饰者对象也实现了Person接口,所以能够在对方法增强的基础上依旧返回一个Person对象,如果其他类想要使用这个Man类的话,我们可以以Person接口引用的方式传过去,让对方感觉不到已经被装饰过了。
好处
那么为什么要使用装饰者模式呢?
同一个接口,一个类在另外一个类基础上实现增强方法,以前是采用继承,为什么要采用装饰者模式
类继承一旦父类改变,那么子类也得相应进行改变,也就是说它们之间的耦合性太高,不利于代码的维护和管理,使用装饰者模式可以将装饰类和被装饰类彼此独立起来,只需要实现共同的接口,一旦需要改代码升级时,只需要更改相应的类就可以了,不需要都改变。
总的来说:使用装饰者模式就是为了:解耦以及提高代码的扩展性和可维护性。