装饰器模式

Posted 臭屁猪

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了装饰器模式相关的知识,希望对你有一定的参考价值。

1. 概述

 

       若你从事过面向对象开发,实现给一个类或对象增加行为,使用继承机制,这是所有面向对象语言的一个基本特性。如果已经存在的一个类缺少某些方法,或者须要给方法添加更多的功能(魅力),你也许会仅仅继承这个类来产生一个新类—这建立在额外的代码上。

      通过继承一个现有类可以使得子类在拥有自身方法的同时还拥有父类的方法。但是这种方法是静态的,用户不能控制增加行为的方式和时机。如果  你希望改变一个已经初始化的对象的行为,你怎么办?或者,你希望继承许多类的行为,改怎么办?前一个,只能在于运行时完成,后者显然时可能的,但是可能会导致产生大量的不同的类—可怕的事情。

 

2. 问题

你如何组织你的代码使其可以容易的添加基本的或者一些很少用到的 特性,而不是直接不额外的代码写在你的类的内部?

3. 解决方案

 

        装饰器模式: 动态地给一个对象添加一些额外的职责或者行为。就增加功能来说, Decorator模式相比生成子类更为灵活。

 

       装饰器模式提供了改变子类的灵活方案。装饰器模式在不必改变原类文件和使用继承的情况下,动态的扩展一个对象的功能。它是通过创建一个包装对象,也就是装饰来包裹真实的对象。

 

       当用于一组子类时,装饰器模式更加有用。如果你拥有一族子类(从一个父类派生而来),你需要在与子类独立使用情况下添加额外的特性,你可以使用装饰器模式,以避免代码重复和具体子类数量的增加。

4. 适用性

以下情况使用Decorator模式

1)? 在不影响其他对象的情况下,以动态、透明的方式给单个对象添加职责。

2)? 处理那些可以撤消的职责。

3)? 当不能采用生成子类的方法进行扩充时。一种情况是,可能有大量独立的扩展,

为支持每一种组合将产生大量的子类,使得子类数目呈爆炸性增长。

另一种情况可能是因为类定义被隐藏,或类定义不能用于生成子类。

5. 结构

uml如图:

技术分享

6.构建模式的组成

抽象组件角色(Component):定义一个对象接口,以规范准备接受附加责任的对象,

即可以给这些对象动态地添加职责。

具体组件角色(ConcreteComponent) :被装饰者,定义一个将要被装饰增加功能的类。

可以给这个类的对象添加一些职责

抽象装饰器(Decorator):维持一个指向构件Component对象的实例,

并定义一个与抽象组件角色Component接口一致的接口

具体装饰器角色(ConcreteDecorator):向组件添加职责。

 7 装饰模式和代理模式很像,但是装饰模式是用于拓展对象的功能,而代理模式用于 控制对象,这个会在代理模式中详细解释

代码演示:

/**一个接口 man类实现了该接口的方法
 * Component 
 * @author re
 *
 */
public interface Person {
	  void eat();
}

  

/**实现了person的接口,现在如果要给person加新功能,需要在接口中增加新方法,然后man来实现
 * 但是,这不符合开闭原则,如果继承man以子类的方式进行扩展,如果功能不定时增加(不是一次性将需要加的功能
 * 全加子类里,而是一段时间加一个,没加一次将产生一个子类),将会产生非常多的
 * 子类,这是后就用到了装饰模式,给一个对象添加额外的职责,也就是功能,并且是在不修改原来已有代码的基础上
 * 新增。好了,现在以person这个接口为主,为man这个是实现类新增功能.
 * ConcreteComponent 
 * @author re
 *
 */
public class Man implements Person {

	@Override
	public void eat() {
		// TODO Auto-generated method stub
		System.out.println("男人在吃");
	}

}

  

/**
 *这里定义一个装饰角色类,持有一个persion。这个person指的是man
 *最好将装饰角色类定义为抽象类(根据具体需求适当改变,没有一定要用),给出指定的抽象方法,让子类去继承实现。
 *这里定义了 beforeEat()这个抽象方法
 * Decorator
 * 
 * @author re
 *
 */
public abstract class Decorator implements Person {

	protected Person person;//这个属性的注入,这里是采用了set注入的方法,也可以建个构造方法进行
	//注入,不过感觉没有使用setPerson()方便
	public void setPerson(Person person) {
		this.person = person;
	}

	@Override
	public void eat() {
		// TODO Auto-generated method stub	
		person.eat();			
	}
	public abstract void beforeEat();
	public abstract void afterEat();

}

  

/**
 * 具体装饰角色类,此类实现了装饰角色类,也有一个与 man里的eat()方法相同的Eat()方法,并且
 * 将新增的方法 如beforeEat()加入了 ManDecoratorA的Eat()方法中,eat()调用了
 * ManDecoratorA的父类也就是Decorator中的eat()方法,而Decorator中的eat()方法则是
 * man里的eat()方法,也就是说完成了对man类的功能扩展
 * @author re
 *
 */
public class ManDecoratorA extends Decorator {
	public void eat() {
		beforeEat();
		super.eat();
		afterEat();
		reEat();
		System.out.println("ManDecoratorA类");
	}

	public void reEat() {
		System.out.println("再吃一顿饭");
	}
	public void beforeEat(){
		
		System.out.println("ManDecoratorA--饭后运动");
	}
	public void afterEat(){
		
		System.out.println("ManDecoratorA--饭前运动");
	}
}

  

/**
 * 与ManDecoratorA性质相同
 * @author re
 *@date 2017年3月28日10:36:54 
 */
public class ManDecoratorB extends Decorator {
	  public void eat() {
		  beforeEat();
	        super.eat();
	        System.out.println("===============");
	        System.out.println("ManDecoratorB类");
	    }

	@Override
	public void afterEat() {
		// TODO Auto-generated method stub
		System.out.println("ManDecoratorB--饭前");
	}

	@Override
	public void beforeEat() {
		// TODO Auto-generated method stub
		System.out.println("ManDecoratorB--饭后");
	}	  
}

  

/**
 * 测试类
 * @author re
 *@date 2017年3月28日10:36:20
 */
public class Test {
	public static void main(String[] args) {
		Man man = new Man();
		ManDecoratorA md1 = new ManDecoratorA();
		ManDecoratorB md2 = new ManDecoratorB();
		md1.setPerson(man);
		md2.setPerson(man);
		md2.eat();
		md1.eat();
		
		String str1="";
		String str2=null;

		
	}

  


以上是关于装饰器模式的主要内容,如果未能解决你的问题,请参考以下文章

设计模式之装饰器模式

装饰器模式问题 - 如何调用嵌套装饰器方法?

学习设计模式之装饰器模式

装饰器模式

PHP 装饰器模式

设计模式之装饰器模式