装饰器模式
被这个模式困惑了一段时间,其实是被一些术语吓到了,其实并没有那么难。
通俗来说,就是一个对象原来有一些功能,然后发现功能不够用,想让这个对象更加强大,就使用一个装饰器对这个对象装饰一下,给其在原有的基础上装饰功能。
实现装饰的核心就是这个对象的装饰前后类型不变,所以被装饰的就应该是一个接口或抽象类类型,被装饰器装饰之后还是可以指向接口或抽象类。
以接口为例
总接口People
:
/**
* 一个人的接口
*/
public interface People {
// 这个人有描述自己的方法
void show();
}
基础的实现,普通人:
/**
* People的基础实现,一无所有的普通人
*/
public class CommonPeople implements People {
@Override
public void show() {
System.out.println("普通人,一无所有");
}
}
三个装饰器,分别为人装饰车、房、对象。
每个装饰器都是调用原People
的方法,然后为其添加本类应该装饰的功能。所有的装饰器都需要实现People
接口(如果采用抽象类实现需要继承抽象类),保证这个对象被装饰之后仍然是People
类型。
/**
* 车装饰器
*/
public class CarDecorator implements People {
private People people;
public CarDecorator(People people) {
this.people = people;
}
@Override
public void show() {
this.people.show();
System.out.println("许多年后,终于有车了");
}
}
/**
* 房装饰器
*/
public class HouseDecorator implements People {
private People people;
public HouseDecorator(People people) {
this.people = people;
}
@Override
public void show() {
this.people.show();
System.out.println("许多年后,终于有房了");
}
}
/**
* 对象装饰器
*/
public class ObjectDecorator implements People {
private People people;
public ObjectDecorator(People people) {
this.people = people;
}
@Override
public void show() {
this.people.show();
System.out.println("许多年后,终于有对象了");
}
}
装饰
public class Main {
public static void main(String[] args) {
// 一无所有的普通人
People people = new CommonPeople();
people.show();
System.out.println("-------------------");
// 这个人有车了
people = new CarDecorator(people);
people.show();
System.out.println("-------------------");
// 这个人有房了
people = new HouseDecorator(people);
people.show();
System.out.println("-------------------");
// 这个人有对象了
people = new ObjectDecorator(people);
people.show();
}
}
运行结果:
如果不使用装饰器,我们无法这么随意地去拓展对象的功能。
如果不使用装饰器,类有什么功能,new
出来的对象就有什么功能。三个装饰器,可以排列组合,有房有车的人,有房有对象的人,随意地为这个对象添加功能,想要什么就加什么。而不是像之前生硬地继承,new
什么就有什么功能。
装饰器使用
说起装饰器,AngularJS
中可是提供了非常详尽的支持,Decorators in AngularJS
就比如AngularJS
中的装饰器,如果是我们自己写的一个Service
,有一天发现功能不够用了,随便改,反正是我自己写的代码。
但是如果你发现第三方库给你提供的Service
方法不够用呢?去改它的代码吗?这是不现实的。
这个慕课网的课程描述了当开发阿里云时,发现UI-Bootstrap
中的一个popover
组件不能自定义模板(现在的UI-Bootstrap
已解决此问题),基于公共组件的开发心得 - 阿里懒懒交流会AngularJS专场
解决方案:
一、改掉它的源代码,自己发布一个库,然后项目中使用这个修改完的库。(没错,阿里的大大们就是这么干的。)
二、设置装饰器,用装饰器为原组件添加新功能。(这个在视频中也提到了,不过是在他们用方案一解决完这个问题时才发现的新方案。偷偷地去看过阿里云中关于popover
弹窗的代码,还是用的方案一,可能时间久了,不好改动。)
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。