程序猿的复仇——Java 中的 Decorator 模式 – 热爱改变生活
我的GitHub GitHub |     登录
  • If you can't fly, then run; if you can't run, then walk; if you can't walk, then crawl
  • but whatever you do, you have to keep moving forward。
  • “你骗得了我有什么用,这是你自己的人生”
  • 曾有伤心之地,入梦如听 此歌

程序猿的复仇——Java 中的 Decorator 模式

模式 sinvader 4193℃ 0评论

1. 什么是 Decorator 模式

修饰模式,是面向对象编程领域中,一种动态地往一个类中添加新的行为的设计模式。就功能而言,修饰模式相比生成子类更为灵活,这样可以给某个对象而不是整个类添加一些功能。
通过使用修饰模式,可以在运行时扩充一个类的功能。原理是:增加一个修饰类包裹原来的类,包裹的方式一般是通过在将原来的对象作为修饰类的构造函数的参数。装饰类实现新的功能,但是,在不需要用到新功能的地方,它可以直接调用原来的类中的方法。修饰类必须和原来的类有相同的接口。
修饰模式是类继承的另外一种选择。类继承在编译时候增加行为,而装饰模式是在运行时增加行为。
当有几个相互独立的功能需要扩充时,这个区别就变得很重要。在有些面向对象的编程语言中,类不能在运行时被创建,通常在设计的时候也不能预测到有哪几种功能组合。这就意味着要为每一种组合创建一个新类。相反,修饰模式是面向运行时候的对象实例的, 这样就可以在运行时根据需要进行组合。一个修饰模式的示例是 JAVA 里的 Java I/O Streams 的实现。
以上引用自 维基百科

2. 为什么使用 Decorator 模式

假设一个窗口系统中的窗口,允许这个窗口内容滚动,我们希望给它添加水平或垂直滚动条。假设窗口通过 “Window” 类实例来表示,并且假设它没有添加滚动条功能。我们可以创建一个子类 “ScrollingWindow” 来提供,或者我们可以创建一个 ScrollingWindowDecorator 来为已存在的 Window 对象添加这个功能。在这点上,只要是解决方案就可以了。 现在我们假设希望选择给我们的窗口添加边框,同样,我们的原始 Window 类不支持。ScrollingWindow 子类现在会造成一个问题,因为它会有效的创建一种新的窗口。如果我们想要给所有窗口添加边框,我们必须创建 WindowWithBorder 和 ScrollingWindowWithBorder 子类。显然,这个问题由于被添加类而变得更糟了。对于修饰模式,我们简单的创建一个新类 BorderedWindowDecorator,在运行时,我们能够使用 ScrollingWindowDecorator 或 BorderedWindowDecorator 或两者结合来修饰已存在的窗口。 一个修饰能够被应用的另一个好例子是当有需要根据某套规则或者几个平行的规则集(不同的用户凭据等)限制访问对象的属性或方法时。
一个对象的属性或方法按照某组规则或几个并行规则 (不同用户证书等) 需要限制访问时,在这种情况下,不是在原始对象中实现访问控制而是在他的使用中不变或不知道任何限制,并且他被包装在一个访问控制修饰对象中,这个对象能够对允许的原始对象的接口子集服务。
以上还是引用自 维基百科 <(* ̄▽ ̄*)/

代码

客户来了,是个大款。

价钱给的很高,老板很开心,嘱咐猿,客户就是上帝,上帝说什么就是什么。 嗻

上帝说话了:我现在想要一个有横向滚动条的窗口

猿:一定会让我写很多窗口的,我定一个接口吧,每个继承再改就好了

interface WindowUsual {
	public void draw(); // 画窗口
	public String getDescription(); // 输出这个窗口的描述
}
class HorScrollBarWindow implements WindowUsual {
	@Override
	public void draw() {
		// 我在画
	}
	@Override
	public String getDescription() {
		return "我用 HorScrollBarWindow 类画了一个带横向滚动条的 window";
	}
}

猿:做好了,上帝你看这个行么?

上帝:改成竖的吧,横向的不好看

猿 (⊙ˍ⊙) 沉默 :好

class VerScrollBarWindow implements WindowUsual {
	@Override
	public void draw() {
		// 我在画
	}
	@Override
	public String getDescription() {
		return "我用 VerScrollBarWindow 画了一个纵向滚动条的 window";
	}
}

猿:上帝,按您的要求做好了(猿特意在 “要求” 两个字上加重了语气)

上帝:咦,和我想的效果不一样啊,试试横竖都来一个,看看好不好看。

猿 (°o°;) 眼看要发工资了,忍忍 :好

class HVScrollBarWindow implements WindowUsual {
	@Override
	public void draw() {
		// 我在画
	}
	@Override
	public String getDescription() {
		return "我用 HVScrollBarWindow 画了一个两个滚动条都有的窗口";
	}
}

猿:上帝,你看你看,两个滚动条的果然好好看,你真有眼光!

上帝不为所动:还是不太好,两个横向的一个纵向的试试。

猿 (○´・д・)ノ 后天发工资 :好

然后猿一直在新建类

上帝一直要求加滚动条

……

然后, 程序猿望着长长的一列类文件,流下了痛苦的泪水,从此遁入空门,学习 Decorator 大法去了。

光阴荏苒、岁月如梭

大法学成归来,程序猿回到了公司,当时的上帝投资失败,成为了一个程序猿,是猿的同事。

猿看到当年的上帝一直在延续写着他的代码,创建着一个接一个的类,冷笑一声。

抽出背后的键盘,解下腰间的鼠标

一行行代码信手拈来

猿嘴里默默的念叨着:你要窗口是么?给你

/**
 * @author sumile
 *	整个系统的基类
 */
interface Window {
	public void draw(); // draws the Window
	public String getDescription(); // returns a description of the Window
}
/**
 * @author sumile
 *	一个普通的窗口没有任何的滚动条
 */
class SimpleWindow implements Window {
	public void draw() {
		// draw window
	}
	public String getDescription() {
		return "simple window";
	}
}

你要横向滚动条是么?给你!

猿一挥长袖,卷起满地的尘土,引起了上帝的注意

/**
 * @author sumile
 *	横状滚动条
 */
class HorizontalScrollBarDecorator extends WindowDecorator {
	public HorizontalScrollBarDecorator(Window decoratedWindow) {
		super(decoratedWindow);
	}

	public void draw() {
		drawHorizontalScrollBar();
		decoratedWindow.draw();
	}

	private void drawHorizontalScrollBar() {
		// draw the horizontal scrollbar
	}

	public String getDescription() {
		return decoratedWindow.getDescription() + ", 添加了一个横状滚动条";
	}
}

猿:你要竖状滚动条是么?给你!

/**
 * @author sumile
 *	第一个添加了竖装滚动条的具体的装饰器
 */
class VerticalScrollBarDecorator extends WindowDecorator {
	public VerticalScrollBarDecorator(Window decoratedWindow) {
		super(decoratedWindow);
	}

	public void draw() {
		drawVerticalScrollBar();
		decoratedWindow.draw();
	}

	private void drawVerticalScrollBar() {
		// draw the vertical scrollbar
	}

	public String getDescription() {
		return decoratedWindow.getDescription() + ", 添加了一个竖状滚动条";
	}
}

敲击键盘的声音化为一曲美妙的音乐

然而,上帝的脸上流露出了不屑:这和我做的有什么区别?

猿扯起嘴角,冷笑一声

abstract class WindowDecorator implements Window {
	/**
	 * 在这里,窗口对象被修饰
	 */
	protected Window decoratedWindow;

	public WindowDecorator(Window decoratedWindow) {
		this.decoratedWindow = decoratedWindow;
	}
}

你要一个纵向两个横向?给你!

Window verticalWindos = new VerticalScrollBarDecorator(new SimpleWindow());
Window horizontalWindow=new HorizontalScrollBarDecorator(verticalWindos);
Window horizontalWindow2=new HorizontalScrollBarDecorator(horizontalWindow);
System.out.println(horizontalWindow2.getDescription());

输出:普通窗口, 添加了一个竖状滚动条, 添加了一个横状滚动条, 添加了一个横状滚动条

键盘开始崩溃,WASD 键已经首先不堪重负,飞了出去。

你要一个横向两个纵向?给你!

Window verticalWindos = new VerticalScrollBarDecorator(new SimpleWindow());
Window verticalWindos2 = new VerticalScrollBarDecorator(verticalWindos);
Window horizontalWindow=new HorizontalScrollBarDecorator(verticalWindos2);
System.out.println(horizontalWindow.getDescription());

输出:普通窗口, 添加了一个竖状滚动条, 添加了一个竖状滚动条, 添加了一个横状滚动条

猿:就算你要 N 个纵向,M 个横向又何妨!

键盘崩坏,屏幕冒出火花,鼠标线已经被猫咬断拉到一旁

猿望着上帝震惊到扭曲的脸,慢慢恢复平静:就算你是上帝又如何

我信佛。

初学,还不是很懂,如果有错误,敬请指出。以上代码的基础来自于维基百科

测试代码下载
¥ 有帮助么?打赏一下~

转载请注明:热爱改变生活.cn » 程序猿的复仇——Java 中的 Decorator 模式


本博客只要没有注明“转”,那么均为原创。 转载请注明链接:sumile.cn » 程序猿的复仇——Java 中的 Decorator 模式

喜欢 (4)
发表我的评论
取消评论
表情

如需邮件形式接收回复,请注册登录

Hi,你需要填写昵称和邮箱~

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址