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

书中写到,装饰者模式的意图是动态的给对象添加一些额外的职责。就增加功能来说,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. Python——深浅Copy

    1. 赋值 赋值:指向同一块内存地址,所以同时改变 l1 = [1,2,3] l2 = l1 l1.append('a') print(l1,l2) # [1, 2, 3, 'a'] [1, 2, 3 ...

  2. 常见企业IT支撑【1、办公网络IP地址规划】

    规划思路如下,可灵活变化

  3. 基于Spring Boot和Spring Cloud实现微服务架构

    官网的技术导读真的描述的很详细,虽然对于我们看英文很费劲,但如果英文不是很差,请选择沉下心去读,你一定能收获好多.我的学习是先从Spring boot开始的,然后接触到微服务架构,当然,这一切最大的启 ...

  4. linux用户,组,文件等操作

    参考: https://blog.csdn.net/chengqiuming/article/details/78601977   , https://www.cnblogs.com/123-/p/4 ...

  5. java web 程序---猜数字游戏

    思路:1.第一个是随机产生的数字,告诉我们去猜  cai.jsp 2.第二个是一个form表单,提交按钮后,将连接到验证页面 test1.jsp 3.第三个是比较猜的数和随机数.对了,提示再玩一次,不 ...

  6. 1、Window.document对象

    1.Window.document对象 一.找到元素: docunment.getElementById("id"):根据id找,最多找一个:    var a =docunmen ...

  7. NGUI的UIPanel、UIButton、AtlasMaker、Widget、Anchor、Tween、RectTransform

    全文请看:http://note.youdao.com/noteshare?id=f7b476be35ec554e311bc13ef60b62ef

  8. Tkinter学习

    from tkinter import * window = Tk() # 创建一个窗口 window.mainloop() # 消息循环,显示窗口 window.title("窗口标题&q ...

  9. Java复习——反射和泛型的复习

    反射 Class类 一个类被类加载器加载到内存之中,占有一片区域,这个空间里的内容就是类的字节码,不同的类的字节码是不一样的,这一个个空间页可以使用类来表示,这就是Class类. 根据这个概念可知:不 ...

  10. 【BZOJ】1008: [HNOI2008]越狱(组合数学)

    题目 题目描述 监狱有连续编号为1...N的N个房间,每个房间关押一个犯人,有M种宗教,每个犯人可能信仰其中一种.如果相邻房间的犯人的宗教相同,就可能发生越狱,求有多少种状态可能发生越狱 输入输出格式 ...