模式的引入
对于绝大多数人而言,房子是一生中必不可少的部分,就从它说起吧。当一个毛坯房交到你手上时,恰如一张带书写的白纸——你可以绘出绚丽多彩的画一样,
你可以选择各式各样的装修风格,也能选择各种不同的地板等等。而不同的风格,不同的地板,恰恰是对房子的一种“装饰”。哎,不提那没影儿的房了,再说下
我们的衣服,不同的衣服穿在身上,总会给人不同的印象,或清新,或成熟,或老成等,那么衣服同样也是在“装饰”穿衣者。
装饰模式
定义
——《GOF》
类图
实现
下面代码中,我们的“抽象组件(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的引用,
并通过构造函数规范了子类的构造行为。这样做的话,个人认为代码会更加简洁。