写在前面:

以下三点,适用于本系列所有文章。

1、同一个故事,从不同的角度看,就可以引申出不同的模式。本系列中所举模式,未必是当前故事是匹配的,还望大家多提意见,一起讨论,一起提高。

2、类图部分只为突出要点,非重点处不必追究细节。如下面的例子人物应为SingleTon,在“吕布”和“武将”两个Class之间再加一层“董卓武将”似乎更合情理。但若面面俱到,则难免喧宾夺主之嫌,故略之。以后各篇也是如此,不便处敬请谅解。

3、文中所举三国故事,细节上多有虚构戏说成分,旨在说明问题,一笑了之,切莫当真。

Decorator模式(1.虎牢关三英战吕布    2.云长降曹受封赏)

第一个例子取材自三国演义第五回《发矫诏诸镇应曹公 破关兵三英战吕布》,说的是十八路诸候大军逼向虎牢关,吕布率部来迎,连胜盟军数员大将。此时张飞出马,原文精彩部分如下“飞抖擞精神,酣战吕布。连斗五十余合,不分胜负。云长见了,把马一拍,舞八十二斤青龙偃月刀,来夹攻吕布。三匹马丁字儿厮杀。战到三十合,战不倒吕布。刘玄德掣双股剑,骤黄鬃马,刺斜里也来助战。这三个围住吕布。转灯儿般厮杀。八路人马,都看得呆了。吕布架隔遮拦不定,看着玄德面上,虚刺一戟,玄德急闪。吕布荡开阵角,倒拖画戟,飞马便回。三个那里肯舍,拍马赶来。八路军兵,喊声大震,一齐掩杀。”

刘关张何以战败吕布?用的正是装饰者(Decorator)模式。

将故事抽象为如下类图

本例中,两员武将“单挑”,每回合本应各发一招,但通过Decorator模式,张飞聚合了关羽,关羽又聚合了刘备。也就是张飞的“单挑”方法,在对外接口不变(吕布不知情)的情况下,被另外添加了新的行为,导致吕布每回合实际受到了三个人的攻击,故而落败。

代码如下:

using  System;

namespace  ConsoleApplication1
{

    public class Client
    {
        [STAThread]
        static void Main(string[] args)
        {

            武将 吕 = new 吕布();

            菜鸟武将 方 = new 方悦();
            菜鸟武将 穆 = new 穆顺();
            菜鸟武将 武 = new 武安国();
            菜鸟武将 公孙 = new 公孙瓒();

            桃园英雄 张 = new 张飞(new 关羽(new 刘备(null)));

            PK(1,吕,方);
            PK(2,吕,穆);
            PK(3,吕,武);
            PK(4,吕,公孙);

            PK(5,吕,张);
            Console.ReadLine();

        }

        private static void PK(int num,武将 吕,武将 诸侯武将)
        {
            Console.WriteLine("第{0}场 1回合:",num);
            吕.单挑();
            诸侯武将.单挑();
            Console.WriteLine("----------------------");
        }

    }


    public abstract class 武将
    {
        public abstract void 单挑();
    }

    public abstract class 十八路诸侯武将 : 武将
    {
    }

    public abstract class 菜鸟武将 : 十八路诸侯武将
    {
    }

    public abstract class 桃园英雄 : 十八路诸侯武将
    {
        protected 桃园英雄 m_兄弟 = null;
        public 桃园英雄(桃园英雄 帮手)
        {
            m_兄弟 = 帮手;
        }
    }

    public class 吕布 : 武将
    {
        public 吕布()
        {}

        public override void 单挑()
        {
            Console.WriteLine("吕布出手!!!");
        }
    }

    方悦、穆顺、武安国、公孙瓒#region 方悦、穆顺、武安国、公孙瓒
    public class 方悦 : 菜鸟武将
    {
        public 方悦()
        {}

        public override void 单挑()
        {
            Console.WriteLine("方悦出手!");
        }
    }

    public class 穆顺 : 菜鸟武将
    {
        public 穆顺()
        {}

        public override void 单挑()
        {
            Console.WriteLine("穆顺出手!");
        }
    }

    public class 武安国 : 菜鸟武将
    {
        public 武安国()
        {}

        public override void 单挑()
        {
            Console.WriteLine("武安国出手!");
        }
    }

    public class 公孙瓒 : 菜鸟武将
    {
        public 公孙瓒()
        {}

        public override void 单挑()
        {
            Console.WriteLine("公孙瓒出手!");
        }
    }

    #endregion

    刘、关、张#region 刘、关、张
    public class 刘备 : 桃园英雄
    {
        public 刘备(桃园英雄 帮手):base(帮手)
        {}

        public override void 单挑()
        {
            Console.WriteLine("刘备出手:尝尝我双股剑的厉害!");
            if (m_兄弟 != null)
                m_兄弟.单挑();
        }
    }

    public class 关羽 : 桃园英雄
    {
        public 关羽(桃园英雄 帮手):base(帮手)
        {}

        public override void 单挑()
        {
            Console.WriteLine("关羽出手:看我青龙偃月刀!");
            if (m_兄弟 != null)
                m_兄弟.单挑();
        }
    }
    public class 张飞 : 桃园英雄
    {
        public 张飞(桃园英雄 帮手):base(帮手)
        {}

        public override void 单挑()
        {
            Console.WriteLine("张飞出手:吃俺老张一矛!");
            if (m_兄弟 != null)
                m_兄弟.单挑();
        }
    }
    #endregion

}

执行效果图如下:

Decorator模式强调的是在不改变现有对象的基础上,动态修饰对象的行为。而且这种行为的添加,对客户端来说是透明(不知情,即客户端不用改动)的。并且,通过继承+聚合的这种结构关系,使得行为可以无限制地修饰下去。

当然Decorator的局限性也很明显。个人觉得,Decorator模式可能更适合于装饰整个新行为的过程中(新行为所在对象创建时和新行为执行时),不与原有行为发生数据冲突的情况。比如说简单的打印报表,报表的主体不变,页头和页尾都可以用不同的样式来修饰,这时用Decorator就比较合适。但如果主体行为是个update数据库的动作,装饰上的新行为也是一些update和delete的动作,这时用Decorator模式就要多加小心,因为前后几次的行为有数据上的共享,很容易出现逻辑不清,特别是装饰和层次再稍微多些的话,更要开发者必须非常清楚整个流程。

就把前面战吕布的例子作个引申:
张飞策马出阵的途中,在路上看见一瓶三鞭酒,张飞心想,“好啊,二哥斩了华雄,喝的也不过是军中的水酒。俺老张运气好,竟能喝到这喝了后一晚上能长一寸胡子的三鞭酒。战情紧急,待俺打发了吕布,再饮也不迟。”所以,张飞上阵,和吕布虚晃了一招,再回头取酒。“咦?找不到了,酒怎么没了,哪里去了?”

酒哪里去了?原来张飞在和吕布单挑时,将关羽聚合出来帮忙,偏偏关羽实例化时的构造函数有这样一段代码

while(吕布未到())
               {
                     if (发现宝贝())
                            捡宝贝();
                     赶路++;
                }

结果就是那瓶三鞭酒自然被云长收入怀中了,而这一切张飞并不知情。

所以,对于有可能发生数据冲突的Decorator模式,开发时应当多考虑一下前因后果。

可能有人要问,在上面的UML图中,桃园英雄向自身聚合的那根线,如果不指向自身,而指向“十八路诸侯武将”会是什么样的效果?

其实两者都是Decorator模式,因适用场合不同,所以结构也略有不同。我们不必拘泥于细节,只要抓住Decorator的本质思想就可以了。

如果那根聚合线指向“十八路诸侯武将”,桃园英雄带的帮手就可以不仅仅是刘关张了,可以包括菜鸟武将,当然了,菜鸟武将是不能继续聚合新的武将的(怎么有点象马和驴交配生了骡子,骡子却不能再生育的感觉啊,呵呵)。这是两者的差别,可以体会一下。

再举个例子,出自《三国演义》第二十五回《屯土山关公约三事 救白马曹操解重围》看下图。

上面的类图,如果在使用时,不聚合新对象的话,相当于没有装饰,就是一个普通的多态形式。

且说关羽入了相府之后,官拜汉寿亭候,三日一小宴,五日一大宴,封赏不绝。

我们看在这里如何是使用Decorator的

第一日  
使者:“封关羽为汉寿亭侯~~~~”。
关羽:“云长受下,多谢丞相!!!”
代码:关羽.受赏(new 侯爵());

第二日  
使者:“送关羽锦袍~~~~”。
关羽:“云长受下,多谢丞相!!!”
代码:关羽.受赏(new 锦袍());

第三日  
使者:“送关羽赤兔马~~~~。”
关羽:“云长受下,多谢丞相!!!等等,马屁股上驮的什么?美女哎,知我者,曹丞相也 ^_^”
代码为:关羽.受赏(new 赤兔马(new 美女()));

封爵送袍都可以声张,送美女不能声张,要给云长留些面子。所以美女要装饰到赤兔马上,若二嫂问起,只答送马便是。

上图中,如果让关羽也实现“丞相封赏”这个接口行不行呢?这样不影响关羽受赏,好象功能还多了点?

这取决于系统实际的需求,不需要的功能最好不要加,不然可能会节外生枝,看下面这个例子。

某日,曹操召夏侯渊来见,“妙才啊,你平日出生忘死,屡立战功,今天终于有空,我可要好好奖励你一番,按单去领赏吧。”曹操抛下一张纸。

夏侯渊捡起来一看,“第一个,美女,我喜欢。第二个,金银,我喜欢。第三个,锦袍,我喜欢。第四个。。。关羽?哇靠,丞相,你当我是Gay啊!”

转载于:https://www.cnblogs.com/lxq/archive/2006/12/22/600707.html

三国演义与设计模式之Decorator模式(1.虎牢关三英战吕布 2.云长降曹受封赏)...相关推荐

  1. python面向对象程序设计实践(高级)——以《三国演义》中三英大战吕布为例

    python面向对象程序设计实践(初级) --以<三国演义>中三英大战吕布为例 设计实现思路: 设计类 定义武器类:武器名,攻击力 定义人物类:继承武器类,姓名,生命值 设计函数简化对象的 ...

  2. python面向对象程序设计实践(初级)——以《三国演义》中三英大战吕布为例

    python面向对象程序设计实践(初级) --以<三国演义>中三英大战吕布为例 设计实现思路: 定义武器类:武器名,攻击力 定义人物类:继承武器类,姓名,生命值 延时函数:延时0.5秒 实 ...

  3. 设计模式:装饰(Decorator)模式

    设计模式之装饰(Decorator)模式 在现实生活中,常常需要对现有产品增加新的功能或美化其外观,如房子装修.相片加相框等.在软件开发过程中,有时想用一些现存的组件.这些组件可能只是完成了一些核心功 ...

  4. 乱砍设计模式之三 -- DECORATOR模式

    DECORATOR中文的意思是装饰,该模式的动机是帮助对象动态的添加一些功能.它强调是为对象而不是为类添加功能.为类添加功能最有效的方式是通过继承来实现,但继承的缺点是不够灵活.下面我们还是通过例子来 ...

  5. Java--23种设计模式之decorator模式

    装饰模式:装饰模式以对客户端透明的方式扩展对象的功能,是继承关系的一个替代方案,提供比继承更多的灵活性.动态给一个对象增加功能,这些功能可以再动态的撤消.增加由一些基本功能的排列组合而产生的非常大量的 ...

  6. JAVA循环嵌套+分支结构游戏---(以《三国演义》中三英大战吕布为例)

    我们做一个java基础学习中关于循环嵌套加分支语句综合应用的破解小游戏--三英大战吕布为例代码如下: package assignment;import java.util.Scanner;publi ...

  7. Decorator模式------装饰边框与被装饰物的一致性

    1. >>不断地为对象装饰的设计模式称为Decorator 模式. 2. 示例程序 >>功能:给文字添加装饰边框.这里所谓的装饰边框是指用" - " &qu ...

  8. 设计模式-Decorator模式

    目录 一个例子(贪玩蓝月) 传统继承实现 装饰器模式实现 对比 总结 Decorator(装饰器)模式属于结构型模式. 比如当其需要三种不同的附加特性,可以为其创建三个派生类.但是若它还需要同时具有其 ...

  9. Java设计模式(7)装饰模式(Decorator模式)

    Decorator常被翻译成"装饰",我觉得翻译成"油漆工"更形象点,油漆工(decorator)是用来刷油漆的,那么被刷油漆的对象我们称decoratee.这 ...

最新文章

  1. Magazine App Demo
  2. 【deeplab】Semantic Image Segmentation with Deep Convolutional Nets and Fully
  3. 0pp0r11如何更改语言_更改电脑日期的方法
  4. shell脚本一键安装JDK及配置环境变量
  5. Running Builds
  6. linux编程问题记录
  7. jsx 调用php,JavaScript_JavaScript的React框架中的JSX语法学习入门教程,什么是JSX? 在用React写组件的 - phpStudy...
  8. (六)Java垃圾回收机制(附带代码示例)
  9. 【总线】一文看懂 I2C 通信协议
  10. android4.4.3版本root,碉堡了!ROOT精灵支持Nexus 5等Android4.4.3机型ROOT
  11. 金蝶云星空二次开发-数据库存查询
  12. github php right way,GitHub - seraph526/php-the-right-way: 收集PHP最佳实践、编码规范和权威学习指南,方便PHP开发者阅读和查找...
  13. echarts地图功能实现及坐标定位
  14. nrf52832 学习笔记(三)蓝牙从机广播
  15. 大数据第一课(满分作业)——泰坦尼克号生存者预测(Titanic - Machine Learning from Disaster)
  16. kendoUI模板概述(template)
  17. Android系统中的输入输出设备
  18. 【iOS】设计尺寸规范(更新至iPhone 11、iPhone 11 Pro、iPhone 11 Pro Max)
  19. 车牌生成代码车牌后5位生成代码
  20. java 定时器 倒计时_定时器倒计时demo

热门文章

  1. 任正非:华为处在危亡关头,员工做好本职工作就是“参战”
  2. 项目中的MD5、盐值加密
  3. 柑橘病虫害识别方案总结
  4. Webpack之Loader原理及自定义Loader
  5. 函数递归调用?看这文就够了!
  6. OPC客户端开发过程整理
  7. 软件工程08组-第四次作业-猫狗大战挑战赛
  8. 赛门铁克Symantec还原ghost系统文件操作(超详细)
  9. 如何用python开发bmi计算器,实例代码
  10. [历年IT笔试题]2014欢聚时代校园招聘笔试题