`
airu
  • 浏览: 267485 次
  • 性别: Icon_minigender_1
  • 来自: 云南
社区版块
存档分类
最新评论

每天一个(设计模式)-- Decorator模式

 
阅读更多
GOF的设计模式,讲的很细,我这里都很粗略。什么意图,别名,参与者,结构,协作,效果等等。。。
我这等小民,也没有那么高深的理论,拾人牙慧就满足了。
模式是死的,运用是活的。

今天讲讲装饰器模式。其实 每个模式的名字都很重要,因为这个名字基本就说明了这个模式用来干什么。当然,装饰器,不是用来装饰的,但是和装饰相关。

比如,我们设计一个窗子,完了,觉得太单调,于是重新加上边框,还觉得单调,那就贴点窗纸吧,如果还是不满意,那么可以糊个纱窗……

如果用程序来实现,我们可能想到这些对象,窗子,加边框的窗子,贴窗纸的窗子(好拗口),加边框贴窗纸的窗子…… 其实这种错误只会在初学者身上犯。

首先,我们的对象的粒度,应该合适,这样通过面向对象的重复利用,组合,就可以实现很多奇怪的东西。这里,我们有必要把窗,窗纸,边框,窗纱等看单独的对象,再细分,发现,其他都是作为装饰品,为窗服务的。于是,一个大概的参与者思路就清晰了。

然后,如何组织这些类呢?由于他们都与窗有关,那么,肯定又一个共同点,我们可以抽象成一个接口。然后,窗,与其他的东西又不一样,那么又可以分别对待。

最后,我们大概可以得出一个结构图了。这里使用标准的装饰器模式的UML:




图中的Component,应该就是要装饰的对象的抽象,注意,饰品也是可以被装饰的,但是必须有一实际的被装饰对象(下面会说明为什么)。
Decorator接口把装饰器隔离出来,表明这些是装饰器。
每个装饰器需要一个可装饰的 被装饰对象,这就是ConcreteComponent了。为了强制要求装饰器必须装饰一个可装饰对象,我们在构造函数里做了要求。
下面就来看一个小例子。本例子完全只是为了说明模式的结构运用,实际的情况只能如有雷同,实属巧合。

一个接口,这是可被装饰对象的统一接口,表明他们能做什么。
public interface VisualComponent {
	public void draw();
}

这是一个可视组件。他的方法就是画出自己。也可以使用抽象类。
某些组件可能有共同的方法。这里为了简化,直接说关键。

public class Pane implements VisualComponent{

	@Override
	public void draw() {
		// TODO Auto-generated method stub
		System.out.println("drawing pane...");
	}

}

这是一块面板,我们省略了绘制过程,并打印出一串字符,表示正在绘制此组件。

接下来,我们就要给这个可视化组件做装饰了。当然,不仅仅是Pane可以被装饰,只要是实现了VisualComponent接口的类都可以被装饰。

首先要有一个装饰器的接口。
public abstract class ComponentDecorator implements VisualComponent{
	protected VisualComponent visualComponent ;
	public ComponentDecorator(VisualComponent vc){
		this.visualComponent = vc;
	}
}


这里使用了抽象类,如果使用接口也可以,直接继承 VisualComponent就行。
之所以使用抽象类,是为了确保子类使用父类的构造函数来完成装饰器应有的职责,那就是我们只是装饰者,应该提供一个被装饰者给我。

接下来,是具体的装饰器了,我们定义两个,这样可以看到使用情况。
首先是一个边框装饰器。
public class BorderDecorator extends ComponentDecorator{
	
	public BorderDecorator(VisualComponent vc){
		super(vc);
	}
	
	@Override
	public void draw() {
		// TODO Auto-generated method stub
		visualComponent.draw();
		System.out.println("draw bording...");
	}

}

可以看到,他所装饰的类,是通过继承父类构造函数来实现的。
在绘制时,我们先绘制父类,然后绘制自己(代码中省略)。

然后再来一个头装饰器,也就是绘制一个顶栏的装饰器。
public class HeaderDecorator extends ComponentDecorator{
	public HeaderDecorator(VisualComponent vc){
		super(vc);
	}
	@Override
	public void draw() {
		// TODO Auto-generated method stub
		visualComponent.draw();
		System.out.println("drawing header...");
	}

}


好了,我们的装饰器好了,现在来看看如何使用。
装饰器模式,通过不同的修饰顺序,我们可以得到不同的结果。这里如何组装,
是使用者决定的。

public class TestMain {

	/**
	 * @param args
	 */
	public static void main(String[] args) {
		// TODO Auto-generated method stub
		VisualComponent vc = new Pane();
		VisualComponent newVC = new HeaderDecorator(new BorderDecorator(vc));
		newVC.draw();
	}

}


看着是不是眼熟,这个其实和java中的I/O很眼熟;

InputStream ins = new BufferedInputStream(new FileInputStream("xx.txt"));


没错,java.io 下的类就是使用了装饰器模式(当然还有其他的比如Adapter)
从网上找到一张图,很能说明问题,相信大家看完以后,对 java.io里的那么多类,会有一个新的认识。



这个图好像是《Head First 设计模式》的吧。。。嘿嘿,我也没看这本书,但是风格很像。

到这里,我们对装饰器模式应该有个大概的认识了。这里,也可以看到,装饰器模式,其实很适合用于链式过滤,每一层都灵活控制。
这点很像OSI的七层协议,每一层,都添加一个头(做个装饰)。
我们也看看自己有什么设计上需要用到装饰器模式的吧,赶快动手试试效果。
  • 大小: 8.6 KB
  • 大小: 47.8 KB
1
0
分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics