参考书籍:设计模式-可复用面向对象软件基础(黑皮书)

书中写到,装饰者模式的意图是动态的给对象添加一些额外的职责。就增加功能来说,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种设计模式之一)的更多相关文章

  1. Java开发中的23种设计模式详解

    [放弃了原文访问者模式的Demo,自己写了一个新使用场景的Demo,加上了自己的理解] [源码地址:https://github.com/leon66666/DesignPattern] 一.设计模式 ...

  2. Java开发中的23种设计模式详解(转)

    设计模式(Design Patterns) ——可复用面向对象软件的基础 设计模式(Design pattern)是一套被反复使用.多数人知晓的.经过分类编目的.代码设计经验的总结.使用设计模式是为了 ...

  3. Java开发中的23种设计模式(转)

    设计模式(Design Patterns) ——可复用面向对象软件的基础 设计模式(Design pattern)是一套被反复使用.多数人知晓的.经过分类编目的.代码设计经验的总结.使用设计模式是为了 ...

  4. c#中的23种设计模式

    C# 23种设计模式汇总 创建型模式 工厂方法(Factory Method) 在工厂方法模式中,工厂方法用来创建客户所需要的产品,同时还向客户隐藏了哪种具体产品类将被实例化这一细节.工厂方法模式的核 ...

  5. Java 23种设计模式

    转自: http://zz563143188.iteye.com/blog/1847029 ; i<count; i++){ list.add(new MailSender()); } } pu ...

  6. 从追MM谈Java的23种设计模式(转)

    从追MM谈Java的23种设计模式    这个是从某个文章转载过来的.但是忘了原文链接.如果知道的,我追加一下. 1.FACTORY-追MM少不了请吃饭了,麦当劳的鸡翅和肯德基的鸡翅都是MM爱吃的东西 ...

  7. java 23种设计模式及具体例子 收藏有时间慢慢看

    设计模式(Design pattern)是一套被反复使用.多数人知晓的.经过分类编目的.代码设计经验的总结.使用设计模式是为了可重用代码.让代码更容易被他人理解.保证代 码可靠性. 毫无疑问,设计模式 ...

  8. JAVA:23种设计模式详解(转)

    设计模式(Design Patterns) ——可复用面向对象软件的基础 设计模式(Design pattern)是一套被反复使用.多数人知晓的.经过分类编目的.代码设计经验的总结.使用设计模式是为了 ...

  9. 从追MM谈Java的23种设计模式

    从追MM谈Java的23种设计模式 1.FACTORY—追MM少不了请吃饭了,麦当劳的鸡翅和肯德基的鸡翅都是MM爱吃的东西,虽然口味有所不同,但不管你带MM去麦当劳或肯 德基,只管向服务员说“来四个鸡 ...

  10. 23种设计模式全解析 (java版本)

    转自:http://blog.csdn.net/longyulu/article/details/9159589 其中PHP常用的五种设计模式分别为:工厂模式,单例模式,观察者模式,策略模式,命令模式 ...

随机推荐

  1. Docker的一些常用

    日常使用的一些命令 1234567891011121314 docker pull mysql:tags // 拉mysql的tag版本 docker run -it -p(端口映射-主机端口:容器端 ...

  2. oracle 卸载操作

    1. 用 oracle 用户登录 如果要再次安装, 最好先做一些备份工作. 包括用户的登录脚本,数据库自动启动关闭的脚本,和 Listener 自动启动的脚本. 要是有可能连创建数据库的脚本也保存下来 ...

  3. Android中处理崩溃异常 (转)

    大家都知道,现在安装Android系统的手机版本和设备千差万别,在模拟器上运行良好的程序安装到某款手机上说不定就出现崩溃的现象,开发者个人不可能购买所有设备逐个调试,所以在程序发布出去之后,如果出现了 ...

  4. CMapStringToPtr添加与释放

    // 创建MapStringToPtr CMapStringToPtr m_prjFiles; CStringList m_fileList; m_fileList.AddTail(_T(" ...

  5. linux命令ls -l的默认排序方式

    差不多快实现完了ls -l,但是在测试阶段发现一个问题,对于包含[a-ZA-Z]之外的字符,系统的排序方式并不一样. 很想了会儿,总算发现原来它的排序方式是无视[a-ZA-Z]之外的字符的 至于怎么发 ...

  6. 【转】用JMeter来测试Tomcat的性能

    JMeter是Apache组织的开放源代码项目,它是功能和性能测试的工具,100%的用java实现,最新的版本是1.9.1,大家可以到http://jakarta.apache.org/jmeter/ ...

  7. 一次hadoop集群机器加内存的运维过程

    由于前期的集群规划问题,导致当前Hadoop集群中的硬件并没有完全利用起来.当前机器的内存CPU比例为2G:1core,但一般的MapReduce任务(数据量处理比较大,逻辑较复杂)的MR两端都需要将 ...

  8. web页面取用户控件页面中服务器控件的值

    用户控件页面后台: public string P_Name { get { return txt_P_name.Value; } set { txt_P_name.Value = value; } ...

  9. eclipse 使用lombok 精简java bean

    前言:             lombok 提供了简单的注解的形式来帮助我们简化消除一些必须有但显得很臃肿的 java 代码.特别是相对于 POJO             lombok 的官方网址 ...

  10. C# 设计模式-工厂模式(Factory)

    1.工厂模式 factory从若干个可能类创建对象. 例如:如果创建一个通信类接口,并有多种实现方式,可以使用factory创建一个实现该接口的对象,factory可以根据我们的选择,来创建适合的对象 ...