`
dwphper
  • 浏览: 17814 次
  • 性别: Icon_minigender_1
  • 来自: 武汉
最近访客 更多访客>>
社区版块
存档分类
最新评论

策略模式之GOF

阅读更多

前言

 

万 事开头难,最近对这句话体会深刻!这篇文章是这个系列正式开始介绍设计模式的第一篇,所以肩负着确定这个系列风格的历史重任,它在我脑袋里默默地酝酿了好 多天,却只搜刮出了一点儿不太清晰的轮廓,可是时间不等人,以后再多“迭代”几次吧!在前面的随笔里,我已经提到了,这个系列准备以《 Head First Design Patterns 》的结构为主线,所以每个模式的核心故事都是取材于此书,在此再次声明一下。不管怎样,宗旨是为了跟大家一起循序渐进地去认识设计模式。

其实策略模式是一个很简单的模式,也是一个很常用的模式,可谓短小精悍。我在介绍这个模式的同时,为了加深大家对 OO 的理解,还会反复强调前面讲过的设计原则和 GRASP 模式。这个系列的文章前后多少会有一些关联的连续性,但是单独一篇文章针对单一模式也一定是独立的,所以不论大家想从前往后连续看也好,还是挑喜欢的跳着看,都没有问题。

“罗嗦了这么多,太唐僧了吧,快点开始吧 ( 烂西红柿和臭鸡蛋从四面八方飞来 )

模拟鸭子

Joe 是一名 OO 程序员,他为一家开发模拟鸭子池塘游戏的公司工作,该公司的主要产品是一种可以模拟展示多种会游泳和呷呷叫的鸭子的游戏。这个游戏是使用标准的面向对象技术开发的,系统里所有鸭子都继承于 Duck 基类 , 系统的核心类图如下:

 

如图所示,在Duck 基类里实现了公共的 quack() swim() 方法,而 MallardDuck RedheadDuck 可以分别覆盖实现自己的 display() 方法,这样即重用了公共的部分,又支持不同子类的个性化扩展。从目前的情况看,这是一个很好的设计,哈!

  

但是,商场如战场,不进则退。 Joe 的公司最近的日子不好过,盗版泛滥,再加上竞争对手的围追堵劫,已经拖欠好几个月工资了。因此,公司高层在一次集体腐~败后,决定一定要给系统增加一些超玄的功能,以彻底击垮竞争对手。经过董事会讨论,最终觉得如果能让鸭子飞起来,那么一定可以给对手致命一击。于是 Joe 的上司对董事们拍着胸脯说:“这没有问题, Joe 是一个 OO 程序员,这对他来说太简单了!我们保证一周内结束战斗。”

接到任务的 Joe 丝毫不敢怠慢,研究了上级的指示以后,发现只要在 Duck 里增加一个 fly() 方法就可以搞定了,这样所有继承 Duck 的鸭子就都拥有了会飞的能力,哈!这回奖金有盼头啦!改进后的系统类图如下:


    Joe的上司很高兴,带着新产品给董事们演示去了 ……   

……

Joe 的上司:“我正在给董事们演示你会飞的鸭子,但是怎么有很多橡皮鸭子也在四处乱飞呢?你在耍我吗?你还想不想混啦?!” ( 此处省略粗话 100 )

Joe 被吓坏了,到手的奖金泡汤了!冷静下来的 Joe 发现,原来在 Duck 类里增加的方法,也同样被继承于 Duck RubberDuck 类继承了,所以就有了会飞的橡皮鸭子,这是严重违反该系统“真实模拟各种鸭子”的原则的!那么该怎么办呢? Joe 很郁闷!他突然想到:如果在 RubberDuck 类里把 fly() 方法重写一下会如何?在 RubberDuck 类的 fly() 里让橡皮鸭子什么都不做,不就一切 OK 了吗!那以后再增加一个木头鸭子呢?它不会飞也不会叫,那不是要再重写 quack() fly() 方法,以后再增加其它特殊的鸭子都要这样,这不是太麻烦了,而且也很混乱。

最终, Joe 认识到使用继承不是办法,因为他的上司通知他,董事会决定以后每 6 个月就会升级一次系统,以应对市场竞争,所以未来的变化会很频繁,而且还不可预知。如果以后靠逐个类去判断是否重写了 quack() fly() 方法来应对变化,显然混不下去!

Joe 这时很迷惑,为什么屡试不爽的继承,在系统维护升级的时候,无法很好地支持重用呢?)

那么使用接口怎么样?我可以把 fly() 方法放在接口里,只有那些会飞的鸭子才需要实现这个接口,最好把 quack() 方法也拿出来放到一个接口里,因为有些鸭子是不会叫的。就像下面这样:



Joe的上司知道后怒了:“你这样做难道是希望所有需要 quack() fly() 方法的鸭子都去重复实现这两个方法的功能吗?就这么几个鸭子还好说,但是我们有几十、上百个鸭子的时候你怎么办?如果某个方法要做一点修改,难道你要重复修改上百遍吗?你是不是疯啦?”

呵呵!如果你是 Joe ,你该怎么办?

我们知道,并不是所有的鸭子都会飞、会叫,所以继承不是正确的方法。但是虽然上面的使用 Flyable 接口的方法,可以解决部分问题 ( 不再有会飞的橡皮鸭子 ) ,但是这个解决方案却彻底破坏了重用,它带来了另一个维护的噩梦!而且还有一个问题我们前面没有提到,难道所有的鸭子的飞行方式、叫声等行为都是一模一样的吗?不可能吧!

说到这里,为了能帮助 Joe 摆脱困境,我们有必要先停下来,重新回顾一些面向对象设计原则。请您告诉我:“什么东西是在软件开发过程中是恒定不变的?”,您想到了吗?对,那就是变化本身,正所谓“计划没有变化快”,所以直面“变化这个事实”才是正道! Joe 面对的问题是,鸭子的行为在子类里持续不断地改变,所以让所有的子类都拥有基类的行为是不适当的,而使用上面的接口的方式,又破坏了代码重用。现在就需要用到我们的第一个设计原则:

Identify the aspects of your application that vary and separate them from what stays the same. ( 找到系统中变化的部分,将变化的部分同其它稳定的部分隔开。 )

换句话说就是:“找到变化并且把它封装起来,稍后你就可以在不影响其它部分的情况下修改或扩展被封装的变化部分。” 尽管这个概念很简单,但是它几乎是所有设计模式的基础,所有模式都提供了使系统里变化的部分独立于其它部分的方法。

OK !现在我们已经有了一条设计原则,那么 Joe 的问题怎么办呢?就鸭子的问题来说,变化的部分就是子类里的行为。所以我们要把这部分行为封装起来,省得它们老惹麻烦!从目前的情况看,就是 fly() quack() 行为总是不老实,而 swim() 行为是很稳定的,这个行为是可以使用继承来实现代码重用的,所以,我们需要做的就是把 fly() quack() 行为从 Duck 基类里隔离出来。我们需要创建两组不同的行为,一组表示 fly() 行为,一组表示 quack() 行为。为什么是两组而不是两个呢?因为对于不同的子类来说, fly() quack() 的表现形式都是不一样的,有的鸭子嘎嘎叫,有的却呷呷叫。有了这两组行为,我们就可以组合出不同的鸭子,例如:我们可能想要实例化一个新的 MallardDuck( 野鸭 ) 实例,并且给它初始化一个特殊类型的飞行行为 ( 野鸭飞行能力比较强 ) 。那么,如果我们可以这样,更进一步,为什么我们不可以动态地改变一个鸭子的行为呢?换句话说,我们将在 Duck 类里包含行为设置方法,所以我们可以说在运行时改变 MallardDuck 的飞行行为,这听起来更酷更灵活了!那么我们到底要怎么做呢?回答这个问题,先要看一下我们的第二个设计原则:

Program to an interface, not an implementation. (面向接口编程,而不要面向实现编程。)

嘿!对于这个原则,不论是耳朵还是眼睛,是不是都太熟悉了!“接口”这个词已经被赋予太多的含义,搞的大家一说点儿屁事就满嘴往外蹦“接口”。那么它到底是什么意思呢?我们这里说的接口是一个抽象的概念,不局限于语言层面的接口 ( 例如 C# 里的 interface) 。一个接口也可以是一个抽象类,或者一个基类也可以看作是一种接口的表现形式,因为基类变量可以用来引用其子类。要点在于,我们在面向接口编程的时候,可以使用多态,那么实际运行的代码只依赖于具体的接口 (interface, 抽象类,基类 ) ,而不管这些接口提供的功能是如何实现的,也就是说,接口将系统的不同部分隔离开来,同时又将它们连接在一起。 我的神啊!接口真是太伟大了! ( 烂西红柿和臭鸡蛋从四面八方飞来 )

OK! 这回该彻底解决 Joe 的问题了!

根据面向接口编程的设计原则,我们应该用接口来隔离鸭子问题中变化的部分,也就是鸭子的不稳定的行为 (fly() quack()) 。我们要用一个 FlyBehavior 接口表示鸭子的飞行行为,这个接口可以有多种不同的实现方式,可以“横”着分,也可以“竖”着分,管它呢!这样做的好处就是我们将鸭子的行为实现在一组独立的类里,具体的鸭子是通过 FlyBehavior 这个接口来调用这个行为的,因为 Duck 只依赖 FlyBehavior 接口,所以不需要管 FlyBehavior 是如何被实现的。如下面的类图, FlyBehavior QuackBehavior 接口都有不同的实现方式!

Joe已经晕了,“你说了这么多,全是大白话,来点代码行不行,我要 C# 的!”。说到这里,我们也该开始彻底改造这个设计了,并会在最后附加部分代码来帮助大家理解。

  

第一步:我们要给 Duck 类增加两个接口类型的实例变量,分别是 flyBehavior quackBehavior ,它们其实就是新的设计里的“飞行”和“叫唤”行为。每个鸭子对象都将会使用各种方式来设置这些变量,以引用它们期望的运行时的特殊行为类型 ( 使用横着飞,吱吱叫,等等 )

第二步:我们还要把 fly() quack() 方法从 Duck 类里移除,因为我们已经把这些行为移到 FlyBehavior QuackBehavior 接口里了。我们将使用两个相似的 PerformFly() PerformQuack() 方法来替换 fly() qucak() 方法,后面你会看到这两个新方法是如何起作用的。

第三步:我们要考虑什么时候初始化 flyBehavior quackBehavior 变量。最简单的办法就是在 Duck 类初始化的时候同时初始化他们。但是我们这里还有更好的办法,就是提供两个可以动态设置变量值的方法 SetFlyBehavior() SetQuackBehavior() ,那么就可以在运行时动态改变鸭子的行为了。

下面是修改后的 Duck 类图:

我们再看看整个设计修改后的类图:


最后大家再看看演示代码,因为代码比较多,就不贴出来了,大家可以下载后参 考: 。下面是演示代码的执行结果:


这就是策略模式

前面说了那么多,现在终于到了正式介绍我们今天的主角的时候啦!此刻心情真是好激动啊!其实我们在前面就是使用 Strategy 模式帮 Joe 度过了难过,真不知道他发了奖金后要怎么感谢我们啊。 OK !下面先看看官方的定义:

The Strategy Pattern defines a family of algorithms,encapsulates each one,and makes them interchangeable. Strategy lets the algorithm vary independently from clients that use it. (策略模式定义了一系列的算法,并将每一个算法封装起来,而且使它们还可以相互替换。策略模式让算法独立于使用它的客户而独立变化。)

怎么样,有了前面 Joe 的经历,这个定义理解起来还不那么太费劲吧?我想凡是认真看到这里的人,应该都能理解的。那么下面再画蛇添足地罗嗦几句,给那些还不太理解的朋友一个机会吧。 J

 

Context( 应用场景 ):

l         需要使用 ConcreteStrategy 提供的算法。

l         内部维护一个 Strategy 的实例。

l         负责动态设置运行时 Strategy 具体的实现算法。

l         负责跟 Strategy 之间的交互和数据传递。

Strategy( 抽象策略类 )

l         定义了一个公共接口,各种不同的算法以不同的方式实现这个接口, Context 使用这个接口调用不同的算法,一般使用接口或抽象类实现。

ConcreteStrategy( 具体策略类 )

l         实现了 Strategy 定义的接口,提供具体的算法实现。

 

还不理解?!我的神啊!那再看看下面的顺序图吧,这是最后的机会啦!

 


应用场景和优缺点

上面我们已经看过了 Strategy 模式的详细介绍,下面我们再来简单说说这个模式的优缺点吧!怎么说呢,人无完人,设计模式也不是万能的,每一个模式都有它的使命,也就是说只有在特定的场景下才能发挥其功效。我们要使用好模式,就必须熟知各个模式的应用场景。

对于 Strategy 模式来说,主要有这些应用场景:

1、  多个类只区别在表现行为不同,可以使用 Strategy 模式,在运行时动态选择具体要执行的行为。 ( 例如 FlyBehavior QuackBehavior)

2、  需要在不同情况下使用不同的策略 ( 算法 ) ,或者策略还可能在未来用其它方式来实现。 ( 例如 FlyBehavior QuackBehavior 的具体实现可任意变化或扩充 )

3、  对客户 (Duck) 隐藏具体策略 ( 算法 ) 的实现细节,彼此完全独立。

 

对于 Strategy 模式来说,主要有如下优点:

1、  提供了一种替代继承的方法,而且既保持了继承的优点 ( 代码重用 ) 还比继承更灵活 ( 算法独立,可以任意扩展 )

2、  避免程序中使用多重条件转移语句,使系统更灵活,并易于扩展。

3、  遵守大部分 GRASP 原则和常用设计原则,高内聚、低偶合。

对于 Strategy 模式来说,主要有如下缺点:

1、  因为每个具体策略类都会产生一个新类,所以会增加系统需要维护的类的数量。

 

    备注:关于场景和优缺点,上面肯定说得不够全面,欢迎大家来补充。

.NET 框架里的应用

Strategy 模式的应用非常广泛,也许大家有意无意之间一直都在使用。这里举一个 .NET 框架里使用 Strategy 模式的例子,象这样的例子其实还有很多,只要大家细心体会就一定会发现的。

如果写过程序,那么 ArrayList 类肯定都会用过吧,那么它的 Sort 方法想必大家也一定不陌生了。 Sort 方法的定义如下:

public virtual void Sort (IComparer comparer )

可以看到 Sort 方法接收一个 IComparer 类型的参数,那么这个 IComparer 接口是做什么用的呢?下面我们看一段程序, 下面的代码示例演示如何使用默认比较器和一个反转排序顺序的自定义比较器,对 ArrayList 中的值进行排序。( 完全引自MSDN ms-help://MS.MSDNQTR.v80.chs/MS.MSDN.v80/MS.NETDEVFX.v20.chs/cpref2/html/M_System_Collections_ArrayList_Sort_1_a2d90598.htm )

 

 1 using  System;
 2 using  System.Collections;
 3
 4 public   class  SamplesArrayList   {
 5  
 6     public   class  myReverserClass : IComparer   {
 7
 8        //  Calls CaseInsensitiveComparer.Compare with the parameters reversed.
 9        int  IComparer.Compare( Object x, Object y )   {
10            return ( ( new  CaseInsensitiveComparer()).Compare( y, x ) );
11       }

12
13    }

14
15     public   static   void  Main()   {
16  
17        //  Creates and initializes a new ArrayList.
18       ArrayList myAL  =   new  ArrayList();
19       myAL.Add(  " The "  );
20       myAL.Add(  " quick "  );
21       myAL.Add(  " brown "  );
22       myAL.Add(  " fox "  );
23       myAL.Add(  " jumps "  );
24       myAL.Add(  " over "  );
25       myAL.Add(  " the "  );
26       myAL.Add(  " lazy "  );
27       myAL.Add(  " dog "  );
28  
29        //  Displays the values of the ArrayList.
30       Console.WriteLine(  " The ArrayList initially contains the following values: "  );
31       PrintIndexAndValues( myAL );
32  
33        //  Sorts the values of the ArrayList using the default comparer.
34       myAL.Sort();
35       Console.WriteLine(  " After sorting with the default comparer: "  );
36       PrintIndexAndValues( myAL );
37
38        //  Sorts the values of the ArrayList using the reverse case-insensitive comparer.
39       IComparer myComparer  =   new  myReverserClass();
40       myAL.Sort( myComparer );
41       Console.WriteLine(  " After sorting with the reverse case-insensitive comparer: "  );
42       PrintIndexAndValues( myAL );
43
44    }

45  
46     public   static   void  PrintIndexAndValues( IEnumerable myList )   {
47        int  i  =   0 ;
48        foreach  ( Object obj  in  myList )
49          Console.WriteLine(  " \t[{0}]:\t{1} " , i ++ , obj );
50       Console.WriteLine();
51    }

52
53 }

54
55
56 /*  
57 This code produces the following output.
58 The ArrayList initially contains the following values:
59         [0]:    The
60         [1]:    quick
61         [2]:    brown
62         [3]:    fox
63         [4]:    jumps
64         [5]:    over
65         [6]:    the
66         [7]:    lazy
67         [8]:    dog
68
69 After sorting with the default comparer:
70         [0]:    brown
71         [1]:    dog
72         [2]:    fox
73         [3]:    jumps
74         [4]:    lazy
75         [5]:    over
76         [6]:    quick
77         [7]:    the
78         [8]:    The
79
80 After sorting with the reverse case-insensitive comparer:
81         [0]:    the
82         [1]:    The
83         [2]:    quick
84         [3]:    over
85         [4]:    lazy
86         [5]:    jumps
87         [6]:    fox
88         [7]:    dog
89         [8]:    brown 
90 */

 

怎么样,大家看出来了吧,其实在这段代码里, ArrayList 相当于 Strategy 模式中的 Context( 应用场景 ) 部分,而 IComparer 相当于 Strategy( 抽象 策略类 ) 部分, myReverserClass 相当于 ConcreteStrategy( 具体 策略类 ) 部分。我们这里抛开 myReverserClass 类的 Compare 方法 如何具体实现不谈,我们只要知道这是一个具体 策略类,它提供了应用场景需要的具体算法,它实现了抽象策略类接口,而应用场景通过 抽象 策略类动态调用到了 具体 策略类中的算法 。哈!所以这是一个十分典型的 Strategy 模式的应用。

基于这个符合 Strategy 模式的结构,我们还可以提供很多种自定义的具体 策略类的实现,只要这些类实现了 IComparer 接口,就可以在运行时动态设置给 ArrayList 类的 Sort 方法,在 Sort 方法中会根据具体 策略类实现的比较算法规则来对 ArrayList 中的数据进行排序。

最后一个设计原则

关于 Strategy 模式的故事讲到这里,应该基本 OK 啦!下面我们再聊些更高层次的东西。什么是更高层次的东西?嘿!当然是设计原则了!在前面总结 Strategy 模式的优点的时候我们提到过, Strategy 模式不仅保留了继承的优点,而且还提供了更灵活的扩展能力。为什么会这样呢? Strategy 模式是怎么做到这一点的呢?哈!这是因为它“上面有人”啊!谁啊?它就是我们下面要介绍的重量级设计原则:

Favor composition over inheritance. (优先使用对象组合,而非类继承)

关于组合和继承,我们只要这样来理解即可:组合是一种“ HAS-A ”关系,而继承是一种“ IS-A ”关系。很明显“ HAS-A ”要比“ IS-A ”更灵活一些。也就是说在创建系统的时候,我们应该优先使用对象组合,因为它不仅可以给你提供更多灵活性和扩展性,而且还使你可以在运行时改变行为 ( 组合不同的对象 ) ,这简直是酷毙了!但是也不是说继承就是不能用,只是说应该把继承应用在相对更稳定,几乎没有变化的地方,例如前面的 Duck 类里的 Swim() 方法,因为可以肯定所有鸭子一定都会游泳,所以就没有必要给这个行为提供基于 Strategy 模式的实现方式,因为那样做除了是程序更复杂以外,没有什么意义。

转载自 : http://www.cnblogs.com/justinw/archive/2007/02/06/641414.html

分享到:
评论

相关推荐

    设计模式精解-GoF 23种设计模式解析附C++.pdf

    设计模式体现的是一种思想,而思想则是指导行为的一切,理解和掌握了设计模式,并不是说记住了23种(或更多)设计场景和解决策略(实际上这也是很重要的一笔财富),实际接受的是一种思想的熏陶和洗礼,等这种思想...

    设计模式 GOF 23

    2.3.3 策略模式 29 2.4 修饰用户界面 29 2.4.1 透明围栏 29 2.4.2 Monoglyph 30 2.4.3 Decorator 模式 32 2.5 支持多种视感标准 32 2.5.1 对象创建的抽象 32 2.5.2 工厂类和产品类 33 2.5.3 Abstract Factory模式 35...

    设计模式精解-GoF 23种设计模式解析附C++代码

    设计模式体现的是一种思想,而思想则是指导行为的一切,理解和掌握了设计模式,并不是说记住了23种(或更多)设计场景和解决策略(实际上这也是很重要的一笔财富),实际接受的是一种思想的熏陶和洗礼,等这种思想...

    设计模式精解(GoF 23 种设计模式解析)

    GoF 23 种设计模式解析 附 C++实现源码。 设计模式体现的是一种思想,而思想则是指导行为的一切,理解和掌握了设计模式,并不是说记住了23种(或更多)设计场景和解决策略(实际上这也是很重要的一笔财富),实际...

    GoF 的 23 种设计模式

    GoF 的 23 种设计模式的分类,现在对各个模式的功能进行介绍。 单例(Singleton)模式:某个类只能生成一个实例,该类提供了一个全局访问点供外部获取该实例,其拓展是有限多例模式。 原型(Prototype)模式:将一...

    设计模式精解-GoF 23种设计模式解析附C++实现源码

    设计模式体现的是一种思想,而思想则是指导行为的一切,理解和掌握了设计模式,并不是说记住了23种(或更多)设计场景和解决策略(实际上这也是很重要的一笔财富),实际接受的是一种思想的熏陶和洗礼,等这种思想...

    C++设计模式(GoF 23种设计解析附C++实现源码)

    掌握了设计模式,并不是说记住了 23 种(或更多)设计场景和解决策略(实际上这也是很 重要的一笔财富),实际接受的是一种思想的熏陶和洗礼,等这种思想融入到了你的思想中 后,你就会不自觉地使用这种思想去进行你...

    C++设计模式之策略模式

    在GOF的《设计模式:可复用面向对象软件的基础》一书中对策略模式是这样说的:定义一系列的算法,把它们一个个封装起来,并且使它们可相互替换。该模式使得算法可独立于使用它的客户而变化。 策略模式为了适应不同的...

    design-patterns:设计模式

    设计模式:主题创作模式[GoF][GoF] [GoF] [GoF] [GoF]结构模式[GoF] [GoF] [GoF] 复合图案[GoF] 装饰图案[GoF]... 中介者模式[GoF] 纪念图案[GoF] 观察者模式[GoF] 状态模式[GoF] 策略模式[GoF] 访客模式[GoF] 模板图案

    设计模式精解-GoF 23 种设计模式解析附 C++实现源码 单最常用的设计模式入门,比如AbstractFactory模式、Adapater模式、Composite模式、Decorator模式、Factory模式、Observer模式、Strategy模式、Template模式等

    设计模式体现的是一种思想,而思想则是指导行为的一切,理解和掌握了设计模式,并不是说记住了23种(或更多)设计场景和解决策略(实际上这也是很重要的一笔财富),实际接受的是一种思想的熏陶和洗礼,等这种思想...

    设计模式部分习题集锦,程序员必看设计模式

    有关于设计模式的部分习题: GOF模式分为几种,每种包含哪些模式?...行为性设计模式:责任链模式,命令模式,解释器模式,迭代器模式,中介者模式,备忘录模式,观察者模式,状态模式,策略者模式,

    设计模式所有实验及实验报告及代码.zip

    27策略模式 28命令模式 29责任链模式 30状态模式 31观察者模式 32中介者模式 33迭代器模式 34访问者模式 35备忘录模式 36解释器模式 37UMLet的使用与类图的设计 38创建型模式应用实验 39结构型模式应用实验 40行为型...

    gof-java-design-patterns:Java示例中所有GOF设计模式的存储库

    书中提到的所有设计模式的列表: 现实示例,类图,源代码,适用性,参考等解释的...策略设计模式 模板方法设计模式 委托模式 从我们的Github存储库下载源代码: https://github.com/RameshMF/gof-java-design-patterns

    Matlab 2008b 中的策略设计模式:由“四人组”定义的策略模式:“设计模式:...的元素”,Gamma 等。-matlab开发

    GoF 将策略模式定义为: 定义一系列算法,封装每个算法,并使它们可以互换。 策略让算法独立于使用它的客户端而变化。 在这个简单的例子中,我们将时间序列数据存储在 TimeSeries 类中(为了简单起见,我刚刚给了...

    Introduction.rar

    GOF(23种设计模式代码实列,主要用于初学者)分为三大类: ...行为模式:模板方法模式、命令模式、迭代器模式、观察者模式、中介者模式、备忘录模式、解释器模式、状态模式、策略模式、职责链模式、访问者模式。

    研磨设计模式(完整带书签).part2.pdf

    第17章 策略模式(Strategy) 第18章 状态模式(State) 第19章 备忘录模式(Memento) 第20章 享元模式(Flyweight) 第21章 解释器模式(Interpreter) 第22章 装饰模式(Decorator) 第23章 职责链模式...

    研磨设计模式(完整带书签).part1.pdf

    第17章 策略模式(Strategy) 第18章 状态模式(State) 第19章 备忘录模式(Memento) 第20章 享元模式(Flyweight) 第21章 解释器模式(Interpreter) 第22章 装饰模式(Decorator) 第23章 职责链模式...

    ASP.NET设计模式-杨明军译(源码)

    那些以前已经体验过设计模式的读者可能希望跳过本书的第ⅰ部分,这部分介绍了gof提出的设计模式以及其他常见设计原则,包括s.o.l.i.d原则和martinfowler的企业设计模式。所有的代码示例均采用c#语言编写,但这些概念...

    设计模式 design pattern

    2.3.3 策略模式 29 2.4 修饰用户界面 29 2.4.1 透明围栏 29 2.4.2 Monoglyph 30 2.4.3 Decorator 模式 32 2.5 支持多种视感标准 32 2.5.1 对象创建的抽象 32 2.5.2 工厂类和产品类 33 2.5.3 Abstract Factory模式 35...

Global site tag (gtag.js) - Google Analytics