装饰者模式

模式的引入

对于绝大多数人而言,房子是一生中必不可少的部分,就从它说起吧。当一个毛坯房交到你手上时,恰如一张带书写的白纸——你可以绘出绚丽多彩的画一样,

你可以选择各式各样的装修风格,也能选择各种不同的地板等等。而不同的风格,不同的地板,恰恰是对房子的一种“装饰”。哎,不提那没影儿的房了,再说下

我们的衣服,不同的衣服穿在身上,总会给人不同的印象,或清新,或成熟,或老成等,那么衣服同样也是在“装饰”穿衣者。

装饰模式

定义

动态地将责任附加到对象上。 若要扩展功能,装饰者提供了比继承更有弹性的替代方案。

                                                                                                                                                        ——《GOF》

类图



l装饰模式中的角色有:
  抽象组件(Component)角色:给出一个抽象接口,以规范准备接收附加责任的对象。
  具体组件(ConcreteComponent)角色:定义一个将要接收附加责任的类。
  装饰(Decorator)角色:持有一个构件(Component)对象的实例,并定义一个与抽象构件接口一致的接口。
  具体装饰(ConcreteDecorator)角色:负责给构件对象“贴上”附加的责任。


实现

下面代码中,我们的“抽象组件(compoment)”是Phone;“具体组件(ConcreteCompoment)”是IPhone,Nokia....等类的对象;“抽象装饰者(Decorator)”是PartsDecorator;

“具体装饰者(ConcreteDecorator)”是HighLightMembrane等等。


package com.decorate;
/**
 * 抽象组件类
 * @author an.yan
 *
 */
public abstract class Phone {
	private String description;
	public String description(){
		return description;
	}
	public abstract double cost();
}

package com.decorate;
/**
 * 具体组件(IPhone)
 * @author an.yan
 *
 */
public class IPhone extends Phone {
	@Override
	public String description() {
		return "I am an iphone";
	}
	@Override
	public double cost() {
		return 4988;
	}
}

package com.decorate;

/**
 * 配件装饰者抽象类
 * 这是具体“配件装饰者”共同实现的接口
 * @author an.yan
 *
 */
public abstract class PartsDecorator extends Phone {
	public abstract String description();

}

package com.decorate;

/**
 * 具体装饰者(磨砂贴膜)
 * @author an.yan
 *
 */
public class FrostedMembrane extends PartsDecorator {

	private Phone phone;

	public FrostedMembrane(Phone phone){
		this.phone=phone;
	}

	@Override
	public String description() {
		return phone.description()+"磨砂贴膜";
	}

	@Override
	public double cost() {
		return 8.19+phone.cost();
	}

}

package com.decorate;

/**
 * 具体装饰者(高亮贴膜)
 * @author an.yan
 *
 */
public class HighLightMembrane extends PartsDecorator {
	private Phone phone;
	public HighLightMembrane(Phone phone){
		this.phone=phone;
	}
	@Override
	public String description() {
		return phone.description()+"高亮贴膜";
	}
	@Override
	public double cost() {
		return 6.19+phone.cost();
	}
}

package com.decorate;

/**
 * 具体装饰者(皮制外壳)
 * @author an.yan
 *
 */
public class LeatherShell extends PartsDecorator {

	private Phone phone;
	public LeatherShell(Phone phone){
		this.phone=phone;
	}
	
	@Override
	public String description() {
		return phone.description()+"皮制外壳";
	}

	@Override
	public double cost() {
		return 61.9+phone.cost();
	}

}

package com.decorate;

/**
 * 具体装饰者(塑料外壳)
 * @author an.yan
 *
 */
public class PlasticShell extends PartsDecorator {

	private Phone phone;
	
	public PlasticShell(Phone phone){
		this.phone=phone;
	}
	
	@Override
	public String description() {
		return phone.description()+"塑料外壳";
	}

	@Override
	public double cost() {
		return 61.9+phone.cost();
	}

}

好了,现在大功告成了。写个测试类:


package com.decorate;

public class Test {

	
	public static void main(String[] args) {
		//实例化一部iphone
		Phone iphone=new IPhone();
		//贴一个磨砂贴膜
		iphone=new FrostedMembrane(iphone);
		//装一个塑料外壳
		iphone=new PlasticShell(iphone);
		System.out.println(iphone.description()+"\n"+iphone.cost());
		
		
		Phone iphoneTwo=new PlasticShell(new IPhone());
		System.out.println(iphoneTwo.description()+"\n"+iphoneTwo.cost());
	}

}


程序中的应用

一个很典型的应用,便是java IO系统,初见java io api,这简直就是类爆炸,一眼望去,百八十个是有的。其实,这不能怪设计者,因为IO系统设计

到的情况总是很多:可以从文件中读入,可以从网络中读入,甚至可以是内存块;可以按照字符读,也可以按照字节读。

事实上,IO让人迷惑的地方在于:创建单一的结果流,却要创建多个对象。就像下面那样:


BufferedInputStream input=null;
		try {
			input=new BufferedInputStream(new FileInputStream(new File("F:/222.txt")));
			while(input.available()>0){
				System.out.println(((char)input.read()));
			}
		} catch (Exception e) {
			e.printStackTrace();
		}finally{
			if(input!=null){
				try {
					input.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
		}

除了创建流的形式不同以外,一般的IO操作是极其类似的:创建流对象,循环读取数据,关闭流。

结合Decorator来看,InputStream的简略类图如下:

o了,很简单的。


读过《HeadFirst》与《java 与模式》这两本书中装饰模式章节的童鞋,应该会发现他们关于Decorator模式的实现,是有区别的。

区别如下:

《HeadFirst》中,每个具体装饰者类中都有一个抽象组件的引用;

而《java与模式》中,他将抽象组件的引用提取到了更高一层,也就是所有具体装饰者的上层接口——抽象装饰者角色。

查看JDK中关于FilterInputStream与BufferedInputStream源码就会发现:FilterInputStream持有一个InputStream的引用,

并通过构造函数规范了子类的构造行为。这样做的话,个人认为代码会更加简洁。



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值