描述:动态的给对象添加一些额外的属性或行为。相比于使用继承,装饰者模式更加灵活。也就是如果想对已经存在的对象进行装饰,那么就定义一个类,在类中对已经有的对象进行功能的增强或添加另外的行为,这个类就叫装饰者类,被修饰的类叫被装饰者类,是已经存在有的功能。在装饰者类之间又可以互相装饰。

装饰装饰,听起名知其意:用土话说,就是给自己打扮下,使其比原来的样子好看下(小编的见解哈)。

java 装饰器 io java设计模式 装饰者模式_ide

 

 要实现装饰者模式,需要了解以下几点内容:

  1. 装饰者类要实现真实类同样的接口;
  2. 装饰者类内有一个真实对象的引用;
  3. 装饰类对象在主类中接收请求,将请求发送给真实的对象;
  4. 装饰者可以在传入真实对象后,增加一些额外的功能。

举例来说明装饰者模式:比如一个程序猿去要去相亲,那他相亲前会做些什么工作呢?肯定会把自己给好好打扮下,让日常糟蹋的自己变得帅点哈。若我们在不了解装饰者前,我们的程序会怎么设计呢?

第一步,我们会先定义一个具有介绍自己和打扮自己的接口:

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();
	}
}


出门前,小张开始打扮自己
穿上西装
穿上皮鞋
系上领带

突然有一天,这个程序猿不知道犯了啥毛病,非要先系领带,再穿西装,最后穿鞋,而我们只需在客户端调整下类的执行顺序就行了,无需再去修改其它类的内部结构了。可见,装饰者模式可以非常灵活地给被装饰者增加一些新的功能。

总结:

  1. 装饰者和被装饰者具有相同的父类型,则在任何需要原始对象(被装饰者)的场合,都可以用装饰过得对象代替原始对象。
  2. 可以用一个或多个装饰者包装一个对象(被装饰者)
  3. 装饰者可以在所委托装饰者行为之前或之后加上一些其他的行为,以达到特定的目的
  4. 被装饰者可以在任何时候被装饰
  5. 装饰类多了,功能相似,出了问题的时候,排错花的时间就长了