设计模式之Decorator(油漆工)
装饰模式 Decorator 常被译成“装饰”,译成油漆工更形象:油漆工(decorator)刷油漆,被刷的对象叫 decoratee。这两种角色在模式里缺一不可。
定义:动态地给一个对象加上额外职责,就像在墙上刷油漆。比起靠生成子类来扩充功能,Decorator 更灵活——功能的种类、时机都可以在运行期由用户决定。
一、为什么不用继承?
继承也能拓展功能,但种类一多就会派生出大量子类,系统变复杂;而且这些功能必须在编译期就预见,是静态的。
Decorator 的理由是:加入方式和时机要由用户动态决定,提供“即插即用”。
| 角色 | 含义 | 本例 |
|---|---|---|
| decoratee | 被刷油漆的对象 | SquarePeg(方形桩) |
| Decorator | 往外再包一层职责 | Decorator(挖坑、钉木板) |
| 共同接口 | 调用方只认接口 | Work.insert() |
二、打桩例子
Adapter 文里有方形桩、圆形桩。Decorator 不关心怎么组合这两个无关类,只关心打桩时额外做的事:挖坑、在桩上钉木板,而且这些步骤可能随时增删改(比如打完再钉架子)。
先定接口:
接口的一个实现——插入方形桩(圆形桩对 Decorator 无所谓,这里只示范方形):
方形桩是 decoratee。把额外功能包进 Decorator,用组合引入 Work:
上例把挖坑、钉木板都排在 insert 前面,只是为了说明次序可以任意安排。调用方式:
三、和 Java I/O 是同一套路
读文件时常见的包一层,其实就是 Decorator:
Java I/O API 正是用 Decorator 拼出来的。I/O 变种极多,若全靠继承会炸出一大片子类。
四、Jive 里的过滤
论坛里有些词不能出现(如“打倒 XXX”),需要过滤或高亮。IBM Java 专栏谈 Jive 时提到 ForumMessageFilter 使用了 Decorator——严格说那份程序还没有真正落地成 Decorator,只是提示:针对特别论坛可以再加过滤,就可以把 ForumMessageFilter 重组为该模式。
判断是不是 Decorator,要抓住定义和两个角色:Decoratee 与 Decorator。
一句话总结:功能要运行期再叠一层,就别狂建子类:用共同接口包住 decoratee,油漆工按需刷上去——Java I/O 就是这样干的。
转载请注明来源:设计模式之Decorator(油漆工)






