DecoratorPattern(23种设计模式之一)
参考书籍:设计模式-可复用面向对象软件基础(黑皮书)
书中写到,装饰者模式的意图是动态的给对象添加一些额外的职责。就增加功能来说,Decorator模式相比生成子类更为灵活。装饰者模式的另一个别名是包装器Wrapper
学习知识常常需要摆脱抽象的理论带给我们的不便,那么最好的方式就是从实践中去理解知识,下面我从传统模式一步一步变换到装饰者模式,这样装饰者模式的好处暴露无遗
模拟QQ秀这一穿衣功能
先看一组代码
传统类
package DecoratorPattern;
public class Person {
private String name;
public Person(String name){
this.name = name;
}
public void wearTshirt(){
System.out.println("T恤");
}
public void wearJeans(){
System.out.println("牛仔裤");
}
public void wearSneakers(){
System.out.println("球鞋");
}
public void wearSuit(){
System.out.println("西装");
}
public void wearTrousers(){
System.out.println("西裤");
}
public void wearLeatherShoes(){
System.out.println("皮鞋");
}
public void show(){
System.out.println("装扮的" + name);
}
}
测试类(客户端类)
package DecoratorPattern;
public class Test {
public static void main(String[] args) {
Person zs = new Person("张三");
System.out.println("第一种装扮:");
zs.wearTshirt();
zs.wearJeans();
zs.wearSneakers();
zs.show();
System.out.println("\n第二种装扮:");
zs.wearSuit();
zs.wearTrousers();
zs.wearLeatherShoes();
zs.show();
}
}
上述代码存在着明显的缺陷,如果现需要不断添加新的衣服,那么就需要频繁的更改原有类Person,这不符合设计原则
现在做一个简单的变化,将展示与穿衣服分开
类图

新的人类
package DecoratorPattern;
public class NewPerson {
private String name;
public NewPerson(String name){
this.name = name;
}
public void show(){
System.out.println("装扮的" + name);
}
}
抽象服饰类
package DecoratorPattern;
public abstract class Finery {
public abstract void show();
}
具体服饰类
package DecoratorPattern.FineryImpl;
import DecoratorPattern.Finery;
public class Jeans extends Finery{
public void show() {
System.out.println("牛仔裤");
}
}
package DecoratorPattern.FineryImpl;
import DecoratorPattern.Finery;
public class LeatherShoes extends Finery {
public void show() {
System.out.println("皮鞋");
}
}
package DecoratorPattern.FineryImpl;
import DecoratorPattern.Finery;
public class Sneakers extends Finery {
public void show() {
System.out.println("球鞋");
}
}
package DecoratorPattern.FineryImpl;
import DecoratorPattern.Finery;
public class Suit extends Finery {
public void show() {
System.out.println("西装");
}
}
package DecoratorPattern.FineryImpl;
import DecoratorPattern.Finery;
public class Trousers extends Finery {
public void show() {
System.out.println("西裤");
}
}
package DecoratorPattern.FineryImpl;
import DecoratorPattern.Finery;
public class TShirts extends Finery{
public void show() {
System.out.println("T恤");
}
}
测试类
package DecoratorPattern;
import DecoratorPattern.FineryImpl.Jeans;
import DecoratorPattern.FineryImpl.LeatherShoes;
import DecoratorPattern.FineryImpl.Sneakers;
import DecoratorPattern.FineryImpl.Suit;
import DecoratorPattern.FineryImpl.TShirts;
import DecoratorPattern.FineryImpl.Trousers;
public class Test1 {
public static void main(String[] args) {
NewPerson zs = new NewPerson("张三");
System.out.println("第一种装扮:");
Finery tx = new TShirts();
Finery nzk = new Jeans();
Finery ax = new Sneakers();
tx.show();
nzk.show();
ax.show();
zs.show();
System.out.println("\n第二种装扮:");
Finery xz = new Suit();
Finery xk = new Trousers();
Finery bx = new LeatherShoes();
xz.show();
xk.show();
bx.show();
zs.show();
}
}
上述解决方式,虽然实现了设计模式的开闭原则,但是依然存在着严重的问题
- 类繁多,这样每增加一个服饰就要增加一个类,不方便
- 展示复杂,我们期望的是内部组装完毕再展示出来
应用装饰者模式,解决如上问题
装饰者模式结构

参与者
Component:组件
ConcreteComponent:具体组件
Decorator:抽象装饰类
ConcreteDecorator:具体装饰类
类图

外观抽象类
package DecoratorPattern;
public abstract class Appearance {
public abstract void show();
}
人
package DecoratorPattern;
public class Person extends Appearance {
private String name;
public Person(String name){
this.name = name;
}
public void show() {
System.out.println("装扮的" + name);
}
}
抽象装饰
package DecoratorPattern;
public abstract class Finery extends Appearance {
protected Appearance component;
public void Decorate(Appearance component){
this.component = component;
}
public void show(){
if(component != null){
component.show();
}
}
}
具体装饰
package DecoratorPattern.FineryImpl;
import DecoratorPattern.Finery;
public class Jeans extends Finery {
public void show(){
super.show();
System.out.println("牛仔裤");
}
}
package DecoratorPattern.FineryImpl;
import DecoratorPattern.Finery;
public class Sneakers extends Finery {
public void show(){
super.show();
System.out.println("球鞋");
}
}
package DecoratorPattern.FineryImpl;
import DecoratorPattern.Finery;
public class TShirt extends Finery {
public void show(){
super.show();
System.out.println("T恤");
}
}
测试类
package DecoratorPattern;
import DecoratorPattern.FineryImpl.Jeans;
import DecoratorPattern.FineryImpl.Sneakers;
import DecoratorPattern.FineryImpl.TShirt;
public class Test {
public static void main(String[] args) {
Person xc = new Person("小菜");
System.out.println("第一种装扮:");
Sneakers ax = new Sneakers();
Jeans nzk = new Jeans();
TShirt tx = new TShirt();
tx.Decorate(xc);
nzk.Decorate(tx);
ax.Decorate(nzk);
ax.show();
}
}
待续
DecoratorPattern(23种设计模式之一)的更多相关文章
- Java开发中的23种设计模式详解
[放弃了原文访问者模式的Demo,自己写了一个新使用场景的Demo,加上了自己的理解] [源码地址:https://github.com/leon66666/DesignPattern] 一.设计模式 ...
- Java开发中的23种设计模式详解(转)
设计模式(Design Patterns) ——可复用面向对象软件的基础 设计模式(Design pattern)是一套被反复使用.多数人知晓的.经过分类编目的.代码设计经验的总结.使用设计模式是为了 ...
- Java开发中的23种设计模式(转)
设计模式(Design Patterns) ——可复用面向对象软件的基础 设计模式(Design pattern)是一套被反复使用.多数人知晓的.经过分类编目的.代码设计经验的总结.使用设计模式是为了 ...
- c#中的23种设计模式
C# 23种设计模式汇总 创建型模式 工厂方法(Factory Method) 在工厂方法模式中,工厂方法用来创建客户所需要的产品,同时还向客户隐藏了哪种具体产品类将被实例化这一细节.工厂方法模式的核 ...
- Java 23种设计模式
转自: http://zz563143188.iteye.com/blog/1847029 ; i<count; i++){ list.add(new MailSender()); } } pu ...
- 从追MM谈Java的23种设计模式(转)
从追MM谈Java的23种设计模式 这个是从某个文章转载过来的.但是忘了原文链接.如果知道的,我追加一下. 1.FACTORY-追MM少不了请吃饭了,麦当劳的鸡翅和肯德基的鸡翅都是MM爱吃的东西 ...
- java 23种设计模式及具体例子 收藏有时间慢慢看
设计模式(Design pattern)是一套被反复使用.多数人知晓的.经过分类编目的.代码设计经验的总结.使用设计模式是为了可重用代码.让代码更容易被他人理解.保证代 码可靠性. 毫无疑问,设计模式 ...
- JAVA:23种设计模式详解(转)
设计模式(Design Patterns) ——可复用面向对象软件的基础 设计模式(Design pattern)是一套被反复使用.多数人知晓的.经过分类编目的.代码设计经验的总结.使用设计模式是为了 ...
- 从追MM谈Java的23种设计模式
从追MM谈Java的23种设计模式 1.FACTORY—追MM少不了请吃饭了,麦当劳的鸡翅和肯德基的鸡翅都是MM爱吃的东西,虽然口味有所不同,但不管你带MM去麦当劳或肯 德基,只管向服务员说“来四个鸡 ...
- 23种设计模式全解析 (java版本)
转自:http://blog.csdn.net/longyulu/article/details/9159589 其中PHP常用的五种设计模式分别为:工厂模式,单例模式,观察者模式,策略模式,命令模式 ...
随机推荐
- NetCore 下集成SignalR并进行分组处理
Tips: 1.注意跟普通版Net.MVC的前端处理方式不一样,以前可以connection.start()后直接done里面再做逻辑处理,现在不行了 建议做法是在具体的业务Hub里重写OnConne ...
- erlang的一些小技巧(不定期更新)
在任意节点热更新代码 rpc:call(Node,c,l,[Mod]) c和l的指的是code,library Erlang Shell隐藏的小技巧 f(). %%把所有绑定变量释放掉 f(Val). ...
- iso网络模型
tcp/ip知识 1.iOS七层模型 应用层 表示层 应用层 ssh httpssl tls ftp mime html snmp 会话层 传输层 传输层 tcp udp 网络层 网络层 ipv6 i ...
- C++代码规范之命名
C++代码规范之命名 一.命名的两个基本原则 1.含义清晰,不易混淆: 2.不和其它模块.系统API的命名空间相冲突. 二.命名通则 1.在所有命名中,都应使用标准的英文单词或缩写:不得使用拼音或拼音 ...
- FPGA的新变化
FPGA SoC通过融合FPGA和ASIC两者的元件,跨越了灵活性和性能之间的界限.但随着它们进入高安全性.任务关键型市场,它们也面临着与标准SoC相同的问题,包括在日益复杂的器件中快速传输越来越多的 ...
- C 语言 - 逻辑运算和短路求值
逻辑运算符: 运算符 含义 优先级 ! 逻辑非 高 && 逻辑与 中 || 逻辑或 低 举例: !a:如果 a 为真,!a 为假:如果 a 为 假,!a 为真 a && ...
- 广义线性模型(Generalized Linear Models)
在线性回归问题中,我们假设,而在分类问题中,我们假设,它们都是广义线性模型的例子,而广义线性模型就是把自变量的线性预测函数当作因变量的估计值.很多模型都是基于广义线性模型的,例如,传统的线性回归模型, ...
- svn删除
[本地删除.然后提交到服务器]与[服务器删除然后本地更新] svn delete svn://路径(目录或文件的全路径) -m “删除备注信息文本” 推荐如下操作: svn delete 文件名 sv ...
- eclipse中导入web项目时,出现转不了项目类型的问题解决方案
解决步骤: 1.进入项目目录,可看到.project文件,文本编辑器打开. 2.找到<natures>...</natures>代码段,加入如下标签内容并保存: <nat ...
- mac 上sed
mac上sed和liunx是不一样的,所以有些指令可能不通用,需要将mac上sed替换成gun的: Install Homebrew First, visit Homebrew homepage an ...