游戏开发设计模式之状态模式 & 有限状态机 & c#委托事件(unity3d 示例实现)

命令模式:游戏开发设计模式之命令模式(unity3d 示例实现)

对象池模式:游戏开发设计模式之对象池模式(unity3d 示例实现)

原型模式:游戏开发设计模式之原型模式 & unity3d JSON的使用(unity3d 示例实现)



说起状态模式游戏开发者们第一个想到的一定是AI的有限状态机FSMs,状态模式确实是实现有限状态机的一种方法。之后还会讲状态机的进阶分层状态机(hierarchical state machines),和pushdown自动机(pushdown automata), 本文就拿人物控制的有限状态机来讲讲状态机模式,本文例子其实是状态模式和观察者模式的组合,通过获取玩家按键消息来改变状态。

如果不使用有限状态机

如果想要你实现一个2d或3d游戏中的人物控制(本文拿2d游戏举例),可以让人物走、跑,相信不少人会这么写:
 
   if (Input.GetKey(KeyCode.D))
        {
…设置方向向右..
            if (Input.GetKey(KeyCode.LeftShift))
            {
..移动..播放跑步动画..
            }
            else
            {
..移动..播放走路动画..
            }

        }
        else if (Input.GetKey(KeyCode.A))
        {
        …设置方向向左..
            if (Input.GetKey(KeyCode.LeftShift))
            {
..移动..播放跑步动画..
            }
            else
            {
..移动..播放走路动画..
            }
        }




然后再加上跳跃功能,怎么办呢,跳跃时肯定不能执行走路的操作播放走路的动画啊,加一个bool判断吧,然后代码变成了这样:
bool isJump = false;
    if (Input.GetKeyDown(KeyCode.W))
{
isJump = true;
}

    if (Input.GetKey(KeyCode.D))
        {
…设置方向向右..
            if (Input.GetKey(KeyCode.LeftShift))
            {
if(!isJump)
..移动..播放跑步动画..
else
..移动..播放跳跃动画..
            }
            else
            {
if(!isJump)
..移动..播放走路动画..
else
..移动..播放跳跃动画..
            }

        }
        else if (Input.GetKey(KeyCode.A))
        {
        …设置方向向左..
if(!isJump)
..移动..播放跑步动画..
else
..移动..播放跳跃动画..
            }
            else
            {
if(!isJump)
..移动..播放走路动画..
else
..移动..播放跳跃动画..
            }
        }


然后我们又希望人物按D键能够实现蹲走,怎么办,再加一个bool,再加判断!
bool isCrouch = false;
    if (Input.GetKeyDown(KeyCode.S))
{
isCrouch = true;
}


bool isJump = false;
    if (Input.GetKeyDown(KeyCode.W)&&! isCrouch)
{
isJump = true;
}

    if (Input.GetKey(KeyCode.D))
        {
…设置方向向右..
            if (Input.GetKey(KeyCode.LeftShift))
            {
if(!isJump&&! isCrouch)
..移动..播放跑步动画..
else if(!isCrouch)
..移动..播放跳跃动画..
else
..移动..播放蹲走动画..
            }
            else
            {
if(!isJump&&! isCrouch)
..移动..播放跑步动画..
else if(!isCrouch)
..移动..播放跳跃动画..
else
..移动..播放蹲走动画..            }

        }
        else if (Input.GetKey(KeyCode.A))
        {
        …设置方向向左..
if(!isJump&&! isCrouch)
..移动..播放跑步动画..
else if(!isCrouch)
..移动..播放跳跃动画..
else
..移动..播放蹲走动画..
            }
            else
            {
if(!isJump&&! isCrouch)
..移动..播放跑步动画..
else if(!isCrouch)
..移动..播放跳跃动画..
else
..移动..播放蹲走动画..
            }
        }



然后再加入攻击,跳劈,潜袭,站防,蹲防,还要再继续添加if else 和bool吗?我们究竟能容忍多少这样纠缠在一起的的ifelse? 稍有不慎会出多少错误?调试起来复杂不?。。。这种方法显然是错误的!有大量复杂的分支,极易出现bug。不过,救星来了,就是有限状态机

一个最简单的有限状态机

阿兰图灵提出的图灵机就是一种状态机,就是指一个抽象的机器,它有一条无限长的纸带TAPE,纸带分成了一个一个的小方格,每个方格有不同的颜色。有一个读写头HEAD在纸带上移来移去。机器头有 一组内部状态,还有一些固定的程序。在每个时刻,机器头都要从当前纸带上读入一个方格信息,然后结合自己的内部状态查找程序表,根据程序输出信息到纸带方格上,并转换自己的内部状态,然后进行移动。

准备工作

状态机需要满足的条件:
1.    一组固定的状态(空闲,行走,跳跃,攻击。。。)
2.    状态机一次只能处在一种状态,最简单的例子,我们不能跳的同时蹲下。
3.    一些玩家输入或者事件发送到状态机,来改变现有状态
4.    状态与状态之间的转换都有一个过渡,在这个过渡中不接受玩家的任何输入,比如从站立到蹲下的过渡中玩家在此时按下跳跃或行走等是没有响应的(被忽略)。

根据上面的条件,我们在写一个状态机之前必须要做的一件事就是—画状态图,这样既可以理清你的思路,方便添加状态与功能,又能使你编程的遗漏减少。
比如我们想实现一个人的走、跑、跳、攻击、防御,状态图可以这么画:
 
 

enum&switch


然后我们完成最精简的状态机,就是enum和switch的组合。
我们需要把一组状态放在enum里,命名就按你需要的状态的名字来命名,比如空闲-idle,还需要一个变量来储存当前控制人物的状态:
    public enum CharacterState
    {
        Idling = 0,
        Walking = 1,
        Jumping = 2,
        acting= 3,
        defending= 4,
}
public CharacterState  heroState = CharacterState. Idling;


设置一个函数handleInput来专门处理判断玩家的输入与状态操作,把这个函数放在update中每帧轮询。
void handleInput()
    {
switch(heroState)
{
case CharacterState. Idling:
…播放空闲动画..
if…Input.GetKey –A,D.
this. heroState = CharacterState. Walking;
else if…Input.GetKey –w.
this. heroState = CharacterState. Jumping;
else if…Input.GetKey –J.
this. heroState = CharacterState. acting;
else if…Input.GetKey –I.
this. heroState = CharacterState. defending;
break;
case CharacterState. Walking:
if…Input.GetKey –A,D.
…CharacterController移动操作..
else…Input.GetKeyUp – A,D…
this. heroState = CharacterState. Idling;
break;
case CharacterState. Jumping:
if(Input.GetKeyUp(KeyCode.W))
…CharacterController移动操作..
if(CharacterController.isGrounded)
{
this. heroState = CharacterState. Idling;
}
break;
case CharacterState. acting:
…播放攻击动画.
chargeTime += Time.timeScale / Time.deltaTime;
if(chargeTime>maxTime)
{
this. heroState = CharacterState. Idling;
chargeTime = 0;
}
break;
case CharacterState. defending:
…播放防御动画.
if(Input.GetKeyUp(KeyCode.I))
this. heroState = CharacterState. Idling;
break;
}
    }


这里又需要通过时间来转换状态的,比如攻击状态,我们按下攻击键,执行一个攻击动画,当动画结束时,我们希望人物能回到空闲状态,此时就需要一个chargeTime变量来记录攻击状态持续了多长时间,在每一帧chargeTime加上这一帧的运行时间,也就是这个动画现在播放了多久,我们获取动画总时间长度来作为maxTime,当chargeTime达到maxTime也就是说明一个攻击动作做完了(一个动画播完了)就会转换到空闲状态,在转换到空间状态时再重置chargeTime为0。
这样可以实现一个简单的状态机,所有状态操作都被整合在一起,原理是轮询当前的状态,处理当前状态操作,接受玩家输入来转换状态。
此时这样一个状态机会出现一个问题,我们控制的人物不能跳起来时不能攻击,而且状态机规定一次只能处在一种状态,所以解决办法为拆分成几个状态机,比如负责移动的为一个状态机,攻击防御为另一个状态机,这两个状态机并发运行,就可以实现跳起攻击,或者潜袭等操作了。
当然,这样的状态机有很多缺点,比如不方便添加新状态,这个函数最终也会越写越长越乱。一种好的实现方式就是把每一个状态和它的操作还有在这个状态时对用户输入的判断,也就是对这一个状态的所有处理都封装在一个类中,这就是状态模式。
在实现状态模式之前,让我们先来了解一下c#的委托与事件。

c#的委托与事件

说起委托与事件,就肯定与观察者模式挂钩了。
delegate委托就是可以用这个委托调用别的类中的一个或多个函数
event事件通常与委托联用,就是事件发送者,通过委托调用事件接收者中的函数,来发送事件到事件接收者
在有限状态机中,我们的发送者是update中的按键,接收者就是等待处理按键的状态对象(后面会讲)。在update中判断玩家输入,再把输入的按键作为事件发送给状态对象处理。就是这么一个过程。
此处就拿攻击方面状态举例
首先我们先写一个EventArgs事件数据类的子类,是事件要传送的消息,也就是我们的接收者-状态对象想要接收的消息,这个消息可以自己定义,在此处,我们希望传送按键信息在接受者中处理
using UnityEngine;
using System.Collections;
using System;

public class InputEventArgs : EventArgs
{
    public string input;
    public string addition1;
    public string addition2;
    public InputEventArgs(string _input, string _addition1, string _addition2)
    {
        this.input = _input;
        this.addition1 = _addition1;
        this.addition2 = _addition2;
    }
}


类中的参数用来存储信息此处的input为按键,addition1,addition2,留空,以便以后开发需要新的信息。作为攻击方面状态addition1,addition2可以是武器的种类(不同的攻击方式,不同的播放动画,不同的技能等等)也可以对组合键加以判断(有些游戏中组合键可以让人物发出某些特殊技能)

然后来看看事件发送者,新建一个hero类专门控制人物状态操作,heroStateActVer储存着当前状态,在update函数中
 
  public delegate void InputEventHandler(object sender, InputEventArgs e);
public event InputEventHandler InputTran;

    InputEventArgs inputArgs = new InputEventArgs("","","");
State heroStateActVer;
    void Start()
    {
        personCtrl = this.GetComponent<HeroCtrl>();
        heroStateActVer = new IdleStateActVer(this.gameObject);
        InputTran += new InputEventHandler(heroStateActVer.handleInput);
    }
    void Input_events(InputEventArgs e)
    {
        if (e != null)
        {
            InputTran(this, e);
        }
    }
    void Update()
{    
        if (Input.anyKeyDown)
        {
            foreach (char c in Input.inputString)
            {
                if (c != null)
                {
                    inputArgs.input = c.ToString();
                    Input_events(inputArgs);
                }
            }
        }
heroStateActVer.UpDate();
}


state的UpDate()存储了对该状态的实时操作,heroStateActVer.UpDate();为处理当前状态该有的操作,比如行走状态就是CharacterController.move,之后我们会讲解
我们在发送类中定义委托与事件,我们接收用户按键,以字符串的形式存储在事件信息类InputEventArgs中把它发给接受者state对象
我们之所以使用foreach,是因为Input.inputString可以接收多个按键,比如A键和D键同时按,Input.inputString就是“ad”,如下图所示,所以我们遍历一帧按下的所有键,来发送消息。
 

然后就是我们的接收类,也是订阅者state,state对象中有一个方法用来接收发送者发来的事件信息,也就是当事件发生时执行的函数
 
  public void handleInput(object sender, InputEventArgs e)
    {
        input = e.input;
        switch (input)
        {
            case "j"://攻击
…转为攻击状态..
                break;
            case "i"://防御
…转为防御状态…
                break;
        }
    }



状态模式

四人帮说:
Allow an object to alter its behavior when its internal state changes. The object will appear to change its class.
当一个对象的状态改变时来改变他的行为。对象将会改变它的类。
继承于父类状态的各个子状态其中的每一个把它的操作还有在这个状态时对用户输入和外部事件的判断,也就是对这一个状态的所有处理都封装在一个类中,对用户输入的判断和外部事件进行处理,如果需要则改变对象的状态。
在这个类中,我们需要,接受事件的方法handleInput(),实时处理当前状态操作的(如move状态就是处理人物移动)Update(),注意我们并没有继承于 MonoBehaviour,所以这里的Update()不是继承于MonoBehaviour的,是我们自己定义的,之后要放在人物发送类中的MonoBehaviour的Update()中执行 。进入状态时的操作Start(),退出状态时的操作Exit()(根据需要可加可不加)
首先我们需要定义一个父类State,让各种状态都继承于他,我们保存人物发送类和操作类的对象,便于在状态中update()里对人物的控制。chargeTime上面讲过,就是一个状态的持续时间。
using UnityEngine;
using System.Collections;
public class State
{
    protected static string input;
    protected GameObject Person;
    protected Hero Person_ctrl;
    protected float chargeTime;
    protected float MaxTime;
    public State(GameObject _Person)
    {
        this.Person = _Person;
        this.Person_ctrl = _Person.GetComponent<Hero>();
    }
    public virtual void handleInput(object sender, InputEventArgs e)
    {
    }
    public virtual void UpDate()
    {
    }
    public virtual void UpDate()
    {
    }
    public virtual void Start()
    {
}
}


Start()函数是在上一个状态结束,开始下一个状态时调用的函数,之调用一次,UpDate()是要放在人物发送类中的UpDate()中实时运行,handleInput在玩家输入按键时被调用处理,负责转换状态,我们把该状态中对应的所有按键的判断放在里面。
然后在来看看子类攻击状态
using UnityEngine;
using System.Collections;

public class ActState : State
{
    public ActState(GameObject _Person)
        : base(_Person)
    {
    }
    public override void Start()
    {
        this.chargeTime = 0.0f;
        this.MaxTime =..攻击动画时间..
..播放攻击动画..
    }
    public override void handleInput(object sender, InputEventArgs e)
    {

        input = e.input;
        switch (input)
        {
            case "j"://连击
                if (chargeTime > MaxTime - 0.1f)
                {
                    Person_ctrl.GetActState(1).Start();
                }
                break;
            case "i": //转换为防御状态
                if (chargeTime > MaxTime - 0.1f)
                {
                    Person_ctrl.SetActState(2);
                    Person_ctrl.GetNowActState().Start();
                }
                break;
        }
    }
    public override void UpDate()
    {
        if (chargeTime < MaxTime)
            chargeTime += Time.timeScale / Time.deltaTime;
        else
        {
            this.chargeTime = 0.0f;
            Person_ctrl.SetActState(0);
            Person_ctrl.GetNowActState().Start();
        }
    }
}


可以看到,在start函数中也就是状态开始,刷新chargeTime,播放攻击动画,在update函数中,更新时间chargeTime,判断是否超过指定时间MaxTime(此处为一次攻击动画时间),如果超过则切换当前状态为空闲,handleInput接收事件输入,object sender是事件发送者,就是例子中的Hero类, InputEventArgs e是传入的按键信息,在该函数中判断是否需要转换状态,或者作出相应操作。所以,状态转换是在我们封装的状态对象中实现的。
我们有两种方法获取状态对象。一种是定义一个状态类,把状态声明为静态来获取, 不需要消耗内存来实例化,想要攻击状态就AllState. actState就可以,:
using UnityEngine;
using System.Collections;

public class AllState
{
public static State actState = new ActState();
public static State jumpState = new JumpState();
…….
}


但是这种方法并不能两个人物共用,状态时间chargeTime是无法公用的,这个问题很关键,所以,还有一种就是在Hero类里实例化状态对象,可以实现多任务共用状态,因为在每个人物类里都有状态的实例。
    private State[] hero_act_state = new State[3];
        hero_act_state[0] = new IdleStateActVer(this.gameObject);
        hero_act_state[1] = new ActState(this.gameObject);
        hero_act_state[2] = new DefenseState(this.gameObject);


然后再写一个get,set方法,使状态变量更加安全,这里不做代码示范了。

总结

在有限状态机中,一般都是观察者模式与状态模式连用,状态模式把每个状态封装成类,来对每个输入消息(按键)处理,完全摆脱了大量if else的纠缠,减轻了大量逻辑错误出现的可能,但是本身也有很多缺点,因为状态毕竟是有限的,,当状态少的时候可以运用自如,当状态多的时候10个以上就已经结构非常复杂,而且容易出错,之前在 游戏人工智能开发之6种决策方法 提到如果用在AI上会产生一些问题,所以之后会发文讲状态机的进阶-分层有限状态机。
本来是写状态模式的,所以不得不提有限状态机,有限状态机当然要包括观察者模式了,所以写本篇的时候思路有些混乱,委托和事件也只是稍微提了一下。。如果有错误,或者是建议请评论或私信。

部分代码已共享至github


命令模式:游戏开发设计模式之命令模式(unity3d 示例实现)

对象池模式:游戏开发设计模式之对象池模式(unity3d 示例实现)

原型模式:游戏开发设计模式之原型模式 & unity3d JSON的使用(unity3d 示例实现)

博主近期渲染:最近用unity5弄的一些渲染


                              ---- by wolf96   http://blog.csdn.net/wolf96



  • 9
    点赞
  • 74
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
1、 FACTORY —追 MM 少不了请吃饭了, 麦当劳的鸡翅和肯德基的鸡翅都是 MM 爱吃的东西, 虽然口味有所不同, 但不管你带 MM 去麦当劳或肯德基, 只管向服务员说“来四个鸡翅”就行 了。麦当劳和肯德基就是生产鸡翅的 Factory 工厂模式:客户类和工厂类分开。消费者任何时候需要某种产品,只需向工厂请求即可。消 工厂模式 费者无须修改就可以接纳新产品。缺点是当产品修改时,工厂类也要做相应的修改。如:如 何创建及如何向客户端提供。 2、BUILDER — MM 最爱听的就是“我爱你”这句话了,见到不同地方的 MM,要能够用她们的 、 方言跟她说这句话哦,我有一个多种语言翻译机,上面每种语言都有一个按键,见到 MM 我只要按对应的键, 它就能够用相应的语言说出“我爱你”这句话了, 国外的 MM 也可以轻松 搞掂,这就是我的“我爱你”builder。 (这一定比美军在 伊拉克用的翻译机好卖) 建造模式: 从而使一个建造过程生成具有不 建造模式 将产品的内部表象和产品的生成过程分割开来, 同的内部表象的产品对象。 建造模式使得产品内部表象可以独立的变化, 客户不必知道产品 内部组成的细节。建造模式可以强制实行一种分步骤进行的建造过程。 3、FACTORY METHOD —请 MM 去麦当劳吃汉堡,不同的 MM 有不同的口味,要每个都记住 、 是一件烦人的事情,我一般采用 Factory Method 模式,带着 MM 到服务员那儿,说“要一个 汉堡”,具体要什么样的汉堡呢,让 MM 直接跟服务员说就行了。 工厂方法模式: 而是将具体创建的工作交给子类去做, 工厂方法模式 核心工厂类不再负责所有产品的创建, 成为一个抽象工厂角色, 仅负责给出具体工厂类必须实现的接口, 而不接触哪一个产品类应 当被实例化这种细节。 4、 、 PROTOTYPE —跟 MM 用 QQ 聊天, 一定要说些深情的话语了, 我搜集了好多肉麻的情话, 需要时只要 copy 出来放到 QQ 里面就行了, 这就是我的情话 prototype 了。 (100 块钱一份, 你要不要) 原始模型模式: 原始模型模式 通过给出一个原型对象来指明所要创建的对象的类型,然后用复制这个原 型对象的方法创建出更多同类型的对象。 原始模型模式允许动态的增加或减少产品类, 产品 类不需要非得有任何事先确定的等级结构, 原始模型模式适用于任何的等级结构。 缺点是每 一个类都必须配备一个克隆方法。 5、 、 SINGLETON —俺有 6 个漂亮的老婆, 她们的老公都是我, 我就是我们家里的老公 Sigleton, 她们只要说道“老公”,都是指的同一个人,那就是我(刚才做了个梦啦,哪有这么好的事) 单例模式: 而且自行实例化并向整个系统提供这个实 单例模式 单例模式确保某一个类只有一个实例, 例单例模式。单例模式只应在有真正的“单一实例”的需求时才可使用。 结构型模式 6、ADAPTER —在朋友聚会上碰到了一个美女 Sarah,从香港来的,可我不会说粤语,她不 、 会说普通话,只好求助于我的朋友 kent 了,他作为我和 Sarah 之间的 Adapter,让我和 Sarah 可以相互交谈了(也不知道他会不会耍我) 适配器模式: 从而使原本因接口原因不 适配器模式 把一个类的接口变换成客户端所期待的另一种接口, 匹配而无法一起工作的两个类能够一起工作。 适配类可以根据参数返还一个合适的实例给客 户端。 7、BRIDGE —早上碰到 MM,要说早上好,晚上碰到 MM,要说晚上好;碰到 MM 穿了件新 、 衣服, 要说你的衣服好漂亮哦, 碰到 MM 新做的发型, 要说你的头发好漂亮哦。 不要问我“早 上碰到 MM 新做了个发型怎么说”这种问题,自己用 BRIDGE 组合一下不就行了 桥梁模式:将抽象化与实现化脱耦,使得二者可以独立的变化,也就是说将他们之间的强关 桥梁模式 联变成弱关联,也就是指在一个软件系统的抽象化和实现化之间使用组合/聚合关系而不是 继承关系,从而使两者可以独立的变化。 8、COMPOSITE —Mary 今天过生日。“我过生日,你要送我一件礼物。”“嗯,好吧,去商店, 、 你自己挑。”“这件 T 恤挺漂亮,买,这条裙子好看,买,这个包也不错, 买。”“喂,买了 三件了呀,我只答应送一件礼物的哦。”“什么呀,T 恤加裙子加包包,正好配成一套呀,小 姐,麻烦你包起来。”“……”,MM 都会用 Composite 模式了,你会了没有? 合成模式:合成模式将对象组织到树结构中,可以用来描述整体与部分的关系。合成模式就 合成模式 是一个处理对象的树结构的模式。 合成模式把部分与整体的
真正电子版 不是扫描的 可以转为word或者txt 书籍目录 目录 第1章基本概念 1 1.1什么是设计模式 2 1.2设计模式的作用 3 1.3GRASP模式的分类 4 1.4GoF设计模式的分类 4 1.5模式的学习阶段 6 第2章负责任地设计对象——GRASP 9 2.1InformationExpert(信息专家) 11 2.2Creator(创造者) 13 2.3LowCoupling(低耦合) 14 2.4HighCohesion(高内聚) 15 2.5Controller(控制器) 17 2.6Polymorphism(多态) 18 2.7PureFabrication(纯虚构) 19 2.8Indirection(间接) 20 2.9ProtectedVariations(受保护变化) 21 第3章GoF-CreationalDesignPatterns创建型设计模式 23 3.1SimpleFactoryPattern(简单工厂模式) 24 3.1.1定义 24 3.1.2现实例子——国旗生产厂 26 3.1.3C#实例1——电子付款系统 26 3.1.4C#实例2——学校登录系统 29 3.1.5Java实例——手机简单工厂 32 3.1.6优势和缺陷 34 3.1.7应用情景 34 3.2FactoryMethodPattern(工厂方法模式) 35 3.2.1定义 35 3.2.2现实例子——兵工厂 36 3.2.3C#实例——多文档系统 37 3.2.4Java实例——扩展了的手机工厂 41 3.2.5优势和缺陷 44 3.2.6应用情景 44 3.3AbstractFactoryPattern(抽象工厂模式) 45 3.3.1定义 45 3.3.2现实例子——扩展了的兵工厂 48 3.3.3C#实例——大陆生态系统 49 3.3.4Java实例——电脑产品 52 3.3.5优势和缺陷 57 3.3.6应用情景 57 3.4BuilderPattern(建造者模式) 58 3.4.1定义 58 3.4.2现实例子——快餐店 60 3.4.3C#实例——车间造车 61 3.4.4Java实例——建造房屋 65 3.4.5优势和缺陷 69 3.4.6应用情景 70 3.5PrototypePattern(原型模式) 70 3.5.1定义 70 3.5.2现实中的拷贝-粘贴 71 3.5.3C#实例——颜色管理器 72 3.5.4Java实例——简单ToolBar 74 3.5.5ShallowCopy与DeepCopy 76 3.5.6优势和缺陷 82 3.5.7应用情景 82 3.6SingletonPattern(单例模式) 82 3.6.1定义 82 3.6.2现?抵械牡ダ??猈indowsTaskManager 83 3.6.3C#实例——负载均衡控制器 84 3.6.4Java实例——系统日志 86 3.6.5DoubleCheckLocking(双检锁) 89 3.6.6优势和缺陷 93 3.6.7应用情景 93 第4章GoF-StructuralDesignPatterns结构型设计模式 95 4.1AdapterPattern(适配器模式) 96 4.1.1定义 96 4.1.2现实中的实例——电脑电源适配器 97 4.1.3C#实例——化学数据银行 98 4.1.4Java实例——清洁系统 102 4.1.5优势和缺陷 104 4.1.6应用情景 104 4.2BridgePattern(桥接模式) 104 4.2.1定义 104 4.2.2现实中的实例——男人的约会 106 4.2.3C#实例——商业对象与数据对象 107 4.2.4Java实例——不同系统的图像处理 112 4.2.5优势和缺陷 114 4.2.6应用情景 115 4.3CompositePattern(组合模式) 115 4.3.1定义 115 4.3.2组合模式的现实应用——资源管理器 117 4.3.3C#实例——图形树状对象结构 118 4.3.4Java实例——文档格式化 121 4.3.5优势和缺陷 124 4.3.6应用情景 125 4.4DecoratorPattern(装饰模式) 125 4.4.1定义 125 4.4.2现实中的装饰模式——相架 126 4.4.3C#实例——图书馆中的项目 127 4.4.4Java实例——自定义JButton 131 4.4.5优势和缺陷 133 4.4.6应用情景 134 4.5FacadePattern(外观模式) 134 4.5.1定义 134 4.5.2现实中的实例——顾客服务员 135 4.5.3C#实例——抵押申请审核 136 4.5.4Java实例——冲茶 139 4.5.5优势和缺陷 143 4.5.6应用情景 143 4.6FlyweightPattern(轻量级模式) 144 4.6.1定义 144 4.6.2实例——中游的四国军棋 146 4.6.3C#实例——文档编辑器 147 4.6.4Java实例——装载图像 151 4.6.5优势和缺陷 154 4.6.6应用情景 154 4.7ProxyPattern(代理模式) 154 4.7.1定义 154 4.7.2几个现实中的实例 156 4.7.3C#实例——数学代理 158 4.7.4Java实例——Socket回声 160 4.7.5优势和缺陷 165 4.7.6应用情景 165 第5章GoF-BehavioralDesignPatterns行为型设计模式 167 5.1ChainofResponsibility(责任链模式) 168 5.1.1定义 168 5.1.2现实中的实例——军情的传递 169 5.1.3C#实例——采购分级审批 170 5.1.4Java实例——智能大厦安全系统 174 5.1.5优势和缺陷 178 5.1.6应用情景 178 5.2CommandPattern(命令模式) 179 5.2.1定义 179 5.2.2现实中的实例——餐馆订菜 180 5.2.3C#实例——简单计算器 181 5.2.4Java实例——总开关 185 5.2.5优势和缺陷 189 5.2.6应用情景 189 5.3InterpreterPattern(解释器模式) 190 5.3.1定义 190 5.3.2现实示例——音乐符号 192 5.3.3C#实例——中国金钱大写转换 192 5.3.4Java实例——自定义程序解释器 197 5.3.5优势和缺陷 204 5.3.6应用情景 205 5.4IteratorPattern(迭代器模式) 205 5.4.1定义 205 5.4.2现实示例——电视节目选择器 206 5.4.3C#实例——遍历例子 207 5.4.4Java实例——两个迭代器 211 5.4.5优势和缺陷 213 5.4.6应用情景 214 5.5MediatorPattern(中介者模式) 214 5.5.1定义 214 5.5.2现实示例——机场控制塔 215 5.5.3C#实例——聊天室 216 5.5.4Java实例——多线程通信 220 5.5.5优势和缺陷 223 5.5.6应用情景 223 5.6MementoPattern(备忘录模式) 223 5.6.1定义 223 5.6.2现实示例——音响均衡器 226 5.6.3C#实例——销售目标 226 5.6.4Java实例——多次Undo(取消)操作 231 5.6.5优势和缺陷 236 5.6.6应用情景 236 5.7ObserverPattern(观察者模式) 236 5.7.1定义 236 5.7.2现实例子——拉登现身了 238 5.7.3C#实例——猫和老鼠 238 5.7.4C#实例——股票变化 241 5.7.5Java实例——监控系统 245 5.7.6优势和缺陷 248 5.7.7应用情景 248 5.8StatePattern(状态模式) 248 5.8.1定义 248 5.8.2现实例子——心情好坏 250 5.8.3C#实例——账户分类 250 5.8.4Java实例——汽车的变速档 258 5.8.5优势和缺陷 261 5.8.6应用情景 261 5.9StrategyPattern(策略模式) 261 5.9.1定义 261 5.9.2现实例子——去机场的策略 263 5.9.3C#实例——排序方法 263 5.9.4Java实例——多格式输出 266 5.9.5优势和缺陷 272 5.9.6应用情景 272 5.10TemplateMethodPattern(模板方法模式) 272 5.10.1定义 272 5.10.2现实例子——厨师烹调 274 5.10.3C#实例——数据库连接模板 274 5.10.4Java实例——冒泡排序模板 277 5.10.5优势和缺陷 280 5.10.6应用情景 280 5.11VisitorPattern(访问者模式) 280 5.11.1定义 280 5.11.2现实例子——收银员收银计费 282 5.11.3C#实例——人事评估 283 5.11.4Java实例——维修工程师检查车辆 287 5.11.5优势和缺陷 291 5.11.6应用情??291 第6章模式的综合应用 293 6.1Java实例——扩展的日志记录器 294 6.2C#实例——存储分析器 298 6.3用模式生成程序架构 316 附录1自测题 321 附录2自测题答案 331
书籍目录 目录 第1章基本概念 1 1.1什么是设计模式 2 1.2设计模式的作用 3 1.3GRASP模式的分类 4 1.4GoF设计模式的分类 4 1.5模式的学习阶段 6 第2章负责任地设计对象——GRASP 9 2.1InformationExpert(信息专家) 11 2.2Creator(创造者) 13 2.3LowCoupling(低耦合) 14 2.4HighCohesion(高内聚) 15 2.5Controller(控制器) 17 2.6Polymorphism(多态) 18 2.7PureFabrication(纯虚构) 19 2.8Indirection(间接) 20 2.9ProtectedVariations(受保护变化) 21 第3章GoF-CreationalDesignPatterns创建型设计模式 23 3.1SimpleFactoryPattern(简单工厂模式) 24 3.1.1定义 24 3.1.2现实例子——国旗生产厂 26 3.1.3C#实例1——电子付款系统 26 3.1.4C#实例2——学校登录系统 29 3.1.5Java实例——手机简单工厂 32 3.1.6优势和缺陷 34 3.1.7应用情景 34 3.2FactoryMethodPattern(工厂方法模式) 35 3.2.1定义 35 3.2.2现实例子——兵工厂 36 3.2.3C#实例——多文档系统 37 3.2.4Java实例——扩展了的手机工厂 41 3.2.5优势和缺陷 44 3.2.6应用情景 44 3.3AbstractFactoryPattern(抽象工厂模式) 45 3.3.1定义 45 3.3.2现实例子——扩展了的兵工厂 48 3.3.3C#实例——大陆生态系统 49 3.3.4Java实例——电脑产品 52 3.3.5优势和缺陷 57 3.3.6应用情景 57 3.4BuilderPattern(建造者模式) 58 3.4.1定义 58 3.4.2现实例子——快餐店 60 3.4.3C#实例——车间造车 61 3.4.4Java实例——建造房屋 65 3.4.5优势和缺陷 69 3.4.6应用情景 70 3.5PrototypePattern(原型模式) 70 3.5.1定义 70 3.5.2现实中的拷贝-粘贴 71 3.5.3C#实例——颜色管理器 72 3.5.4Java实例——简单ToolBar 74 3.5.5ShallowCopy与DeepCopy 76 3.5.6优势和缺陷 82 3.5.7应用情景 82 3.6SingletonPattern(单例模式) 82 3.6.1定义 82 3.6.2现?抵械牡ダ??猈indowsTaskManager 83 3.6.3C#实例——负载均衡控制器 84 3.6.4Java实例——系统日志 86 3.6.5DoubleCheckLocking(双检锁) 89 3.6.6优势和缺陷 93 3.6.7应用情景 93 第4章GoF-StructuralDesignPatterns结构型设计模式 95 4.1AdapterPattern(适配器模式) 96 4.1.1定义 96 4.1.2现实中的实例——电脑电源适配器 97 4.1.3C#实例——化学数据银行 98 4.1.4Java实例——清洁系统 102 4.1.5优势和缺陷 104 4.1.6应用情景 104 4.2BridgePattern(桥接模式) 104 4.2.1定义 104 4.2.2现实中的实例——男人的约会 106 4.2.3C#实例——商业对象与数据对象 107 4.2.4Java实例——不同系统的图像处理 112 4.2.5优势和缺陷 114 4.2.6应用情景 115 4.3CompositePattern(组合模式) 115 4.3.1定义 115 4.3.2组合模式的现实应用——资源管理器 117 4.3.3C#实例——图形树状对象结构 118 4.3.4Java实例——文档格式化 121 4.3.5优势和缺陷 124 4.3.6应用情景 125 4.4DecoratorPattern(装饰模式) 125 4.4.1定义 125 4.4.2现实中的装饰模式——相架 126 4.4.3C#实例——图书馆中的项目 127 4.4.4Java实例——自定义JButton 131 4.4.5优势和缺陷 133 4.4.6应用情景 134 4.5FacadePattern(外观模式) 134 4.5.1定义 134 4.5.2现实中的实例——顾客服务员 135 4.5.3C#实例——抵押申请审核 136 4.5.4Java实例——冲茶 139 4.5.5优势和缺陷 143 4.5.6应用情景 143 4.6FlyweightPattern(轻量级模式) 144 4.6.1定义 144 4.6.2实例——中游的四国军棋 146 4.6.3C#实例——文档编辑器 147 4.6.4Java实例——装载图像 151 4.6.5优势和缺陷 154 4.6.6应用情景 154 4.7ProxyPattern(代理模式) 154 4.7.1定义 154 4.7.2几个现实中的实例 156 4.7.3C#实例——数学代理 158 4.7.4Java实例——Socket回声 160 4.7.5优势和缺陷 165 4.7.6应用情景 165 第5章GoF-BehavioralDesignPatterns行为型设计模式 167 5.1ChainofResponsibility(责任链模式) 168 5.1.1定义 168 5.1.2现实中的实例——军情的传递 169 5.1.3C#实例——采购分级审批 170 5.1.4Java实例——智能大厦安全系统 174 5.1.5优势和缺陷 178 5.1.6应用情景 178 5.2CommandPattern(命令模式) 179 5.2.1定义 179 5.2.2现实中的实例——餐馆订菜 180 5.2.3C#实例——简单计算器 181 5.2.4Java实例——总开关 185 5.2.5优势和缺陷 189 5.2.6应用情景 189 5.3InterpreterPattern(解释器模式) 190 5.3.1定义 190 5.3.2现实示例——音乐符号 192 5.3.3C#实例——中国金钱大写转换 192 5.3.4Java实例——自定义程序解释器 197 5.3.5优势和缺陷 204 5.3.6应用情景 205 5.4IteratorPattern(迭代器模式) 205 5.4.1定义 205 5.4.2现实示例——电视节目选择器 206 5.4.3C#实例——遍历例子 207 5.4.4Java实例——两个迭代器 211 5.4.5优势和缺陷 213 5.4.6应用情景 214 5.5MediatorPattern(中介者模式) 214 5.5.1定义 214 5.5.2现实示例——机场控制塔 215 5.5.3C#实例——聊天室 216 5.5.4Java实例——多线程通信 220 5.5.5优势和缺陷 223 5.5.6应用情景 223 5.6MementoPattern(备忘录模式) 223 5.6.1定义 223 5.6.2现实示例——音响均衡器 226 5.6.3C#实例——销售目标 226 5.6.4Java实例——多次Undo(取消)操作 231 5.6.5优势和缺陷 236 5.6.6应用情景 236 5.7ObserverPattern(观察者模式) 236 5.7.1定义 236 5.7.2现实例子——拉登现身了 238 5.7.3C#实例——猫和老鼠 238 5.7.4C#实例——股票变化 241 5.7.5Java实例——监控系统 245 5.7.6优势和缺陷 248 5.7.7应用情景 248 5.8StatePattern(状态模式) 248 5.8.1定义 248 5.8.2现实例子——心情好坏 250 5.8.3C#实例——账户分类 250 5.8.4Java实例——汽车的变速档 258 5.8.5优势和缺陷 261 5.8.6应用情景 261 5.9StrategyPattern(策略模式) 261 5.9.1定义 261 5.9.2现实例子——去机场的策略 263 5.9.3C#实例——排序方法 263 5.9.4Java实例——多格式输出 266 5.9.5优势和缺陷 272 5.9.6应用情景 272 5.10TemplateMethodPattern(模板方法模式) 272 5.10.1定义 272 5.10.2现实例子——厨师烹调 274 5.10.3C#实例——数据库连接模板 274 5.10.4Java实例——冒泡排序模板 277 5.10.5优势和缺陷 280 5.10.6应用情景 280 5.11VisitorPattern(访问者模式) 280 5.11.1定义 280 5.11.2现实例子——收银员收银计费 282 5.11.3C#实例——人事评估 283 5.11.4Java实例——维修工程师检查车辆 287 5.11.5优势和缺陷 291 5.11.6应用情??291 第6章模式的综合应用 293 6.1Java实例——扩展的日志记录器 294 6.2C#实例——存储分析器 298 6.3用模式生成程序架构 316 附录1自测题 321 附录2自测题答案 331 参考文献 337

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值