描述:动态的给对象添加一些额外的属性或行为。相比于使用继承,装饰者模式更加灵活。也就是如果想对已经存在的对象进行装饰,那么就定义一个类,在类中对已经有的对象进行功能的增强或添加另外的行为,这个类就叫装饰者类,被修饰的类叫被装饰者类,是已经存在有的功能。在装饰者类之间又可以互相装饰。
装饰装饰,听起名知其意:用土话说,就是给自己打扮下,使其比原来的样子好看下(小编的见解哈)。
要实现装饰者模式,需要了解以下几点内容:
- 装饰者类要实现真实类同样的接口;
- 装饰者类内有一个真实对象的引用;
- 装饰类对象在主类中接收请求,将请求发送给真实的对象;
- 装饰者可以在传入真实对象后,增加一些额外的功能。
举例来说明装饰者模式:比如一个程序猿去要去相亲,那他相亲前会做些什么工作呢?肯定会把自己给好好打扮下,让日常糟蹋的自己变得帅点哈。若我们在不了解装饰者前,我们的程序会怎么设计呢?
第一步,我们会先定义一个具有介绍自己和打扮自己的接口:
public interface Person {
/**
* 介绍自己(见面前想好怎么介绍自己才能给对方留下好印象)
* */
void introduce();
/**
* 打扮自己
* */
void dress();
}
第二步,定义一个具体的实现类:
/**
* 定义一个具体的对象:程序员
* */
public class Programmer implements Person{
private String name;
public Programmer(String name) {
this.name = name;
}
@Override
public void introduce() {
System.out.println("你好,我叫"+name);
}
@Override
public void dress() {
System.out.println("出门前,我开始打扮自己");
wearSuit();
wearLeatherShoes();
wearTie();
System.out.println("打扮完毕,开始出门");
}
private void wearSuit() {
System.out.println("穿上西装");
}
private void wearTie() {
System.out.println("系上领带");
}
private void wearLeatherShoes() {
System.out.println("穿上皮鞋");
}
}
程序猿刚到车站,发现自己忘记穿衬衣了,咋办?只能再回去穿咯。接着我们会在程序员类中,再加一个穿衬衣的方法,再在打扮的方法中把这个方法给实现,仔细想想这样的逻辑有问题么?想来想去,发现代码设计上不符合开闭原则。
那我们了解了装饰者模式后,我们又会怎么去设计我们的程序呢?
第一步,我们会先定义一个具有介绍自己和打扮自己的接口:
public interface Person {
/**
* 介绍自己(见面前想好怎么介绍自己才能给对方留下好印象)
* */
void introduce();
/**
* 打扮自己
* */
void dress();
}
第二步,定义一个具体的实现类(被装饰者):
/**
* 定义一个具体的对象:程序员
* */
public class Programmer implements Person{
private String name;
public Programmer(String name) {
this.name = name;
}
@Override
public void introduce() {
System.out.println("你好,我叫"+name);
}
@Override
public void dress() {
System.out.println("出门前,"+name+"开始打扮自己");
}
}
第三步,定义一个装饰类:
/**
* 定义一个装饰类:服装类
* UML图中的Decorator
* */
public class FineryDecorator implements Person{
@Override
public void introduce() {
}
@Override
public void dress() {
}
}
第四步,定义具体的装饰类:
/**
* 定义西装装饰类
* */
public class SuitDecorator extends FineryDecorator{
Person person;//被装饰者对象
public SuitDecorator(Person person) {
this.person = person;
}
@Override
public void introduce() {
person.introduce();
}
@Override
public void dress() {
person.dress();
wearSuit();
}
private void wearSuit() {
System.out.println("穿上西装");
}
}
/**
* 定义领带装饰类
* */
public class TieDecorator extends FineryDecorator{
Person person;//被装饰者对象
public TieDecorator(Person person) {
this.person = person;
}
@Override
public void introduce() {
person.introduce();
}
@Override
public void dress() {
person.dress();
wearTie();
}
private void wearTie() {
System.out.println("系上领带");
}
}
/**
* 定义皮鞋装饰类
* */
public class LeatherShoesDecorator extends FineryDecorator{
Person person;//被装饰者对象
public LeatherShoesDecorator(Person person) {
this.person = person;
}
@Override
public void introduce() {
person.introduce();
}
@Override
public void dress() {
person.dress();
wearLeatherShoes();
}
private void wearLeatherShoes() {
System.out.println("穿上皮鞋");
}
}
第五步,客户端调用:
public class Client {
public static void main(String[] args) {
Person p = new Programmer("小张");
//穿上西装
SuitDecorator suit = new SuitDecorator(p);
//穿上皮鞋
LeatherShoesDecorator shoes = new LeatherShoesDecorator(suit);
//系上领带
TieDecorator tie = new TieDecorator(shoes);
tie.dress();
}
}
出门前,小张开始打扮自己
穿上西装
穿上皮鞋
系上领带
突然有一天,这个程序猿不知道犯了啥毛病,非要先系领带,再穿西装,最后穿鞋,而我们只需在客户端调整下类的执行顺序就行了,无需再去修改其它类的内部结构了。可见,装饰者模式可以非常灵活地给被装饰者增加一些新的功能。
总结:
- 装饰者和被装饰者具有相同的父类型,则在任何需要原始对象(被装饰者)的场合,都可以用装饰过得对象代替原始对象。
- 可以用一个或多个装饰者包装一个对象(被装饰者)
- 装饰者可以在所委托装饰者行为之前或之后加上一些其他的行为,以达到特定的目的
- 被装饰者可以在任何时候被装饰
- 装饰类多了,功能相似,出了问题的时候,排错花的时间就长了