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常用的五种设计模式分别为:工厂模式,单例模式,观察者模式,策略模式,命令模式 ...
随机推荐
- Web API 路由访问设置
前段时间一直致力于MVC webapi 技术的研究,中途也遇到过好多阻碍,特别是api路由的设置和URL的访问形式,所以针对这个问题,特意做出了记录,以供日后有同样困惑的大虾们借鉴: 在Mvc WEB ...
- Google Cloud IAM中添加自定义域名
Google Cloud支持在IAM中加入自定义域名.具体方法如下: 1. 登录Google Cloud Console,点击IAM和管理,进入身份和组织 2. 点击注册 3. 会重定向到Gmail到 ...
- erlang的格式化字符串
往pgsql里面写数据的时候,不能双引号,开始纠结的不行,用拼字符串的形式,后来发现可以格式化字符串,泪奔 data_format.erl -module(data_format). -export( ...
- JVM内存管理之GC算法精解(五分钟让你彻底明白标记/清除算法)
相信不少猿友看到标题就认为LZ是标题党了,不过既然您已经被LZ忽悠进来了,那就好好的享受一顿算法大餐吧.不过LZ丑话说前面哦,这篇文章应该能让各位彻底理解标记/清除算法,不过倘若各位猿友不能在五分钟内 ...
- jquery json string 转换 合并
Jquery 1.9.1 var BODY = { "recipients": { "values": [] }, "subject": ' ...
- 报错:Can't find a source file at "xxxxx“Locate the file or edit the source lookup path to include its location.
调试问题: Can't find a source file at "/tmp/TI_MKLIB6sLCzz/SRC/exit.c" Locate the file or edit ...
- 关于标签的属性-<a>
标签的属性可以分成两个大类 1.系统属性名:例如 id class src这些都是系统里自带的 2.自定义属性名:可以根据使用的需要自行定义 下面我们简短介绍一下<a>标签的使用 < ...
- 跨境B2B电商
主要处理问题:解决整个支付和流通环节,各国双方的供应商和销售商只关注下单支付后就可以拿到货物,中间环节由平台处理,支付和流通环节消费越少速度越快服务越好. 主体业务 1.合同处理. 2.货币支付,互换 ...
- Nginx压力测试工具之WebBench
Nginx压力测试工具之WebBench 在Apache中有自带的ab命令可以测试服务的压力,而nginx没有自带的命令,必须要采用第三方软件来测试,今天就简单介绍一下webbench对nginx ...
- 为什么KVM计算机点无故重启?
一.故障1:机器hangs 本地一台cloudstack计算节点无故连不上了,cloudstack也坏了,后查看有一台系统虚拟机在这台计算节点上,导致cs挂了.去找到这台机器后,发现这台机器卡住了,重 ...