设计模式

1.状态模式(State)

解释:让一个对象的行为随着内部状态的改变而变化,而该对象也像是换了类一样。
结构图
在这里插入图片描述

  • Context(状态拥有者)
    是一个具有“状态”的属性类,可以制定相关的接口,让外界能够得知状态的改变或通过操作让状态改变。
    有状态的属性类,例如:游戏角色具有潜行、攻击、施法等状态;好友上线、脱机、忙碌等状态。
  • State(状态接口类):制定状态的接口,负责规范Context在特定状态下要表现得行为。
  • ContextState(具体状态类)继承至State。
    实现Context在特定状态下该有的行为,例如,角色在潜行状态时该有的行动变缓等。

实现范例

public class Context
{
    private State mState;
    public void Request(int value)
    {
        mState.Handle(value);
    }
    public void SetState(State state)
    {
        mState = state;
    }
}

Context类中,拥有一个State属性来代表当前的状态,外界可以通过Request方法,让Context类
呈现当前状态下的行为。SetState方法可以指定Context类当前的状态,而State状态接口类则用来定义每一个状态下的行为:

public abstract class State
{
    protected Context mContext = null;
    public State(Context theContext)
    {
        mContext = theContext;
    }
    public abstract void Handle(int value);
}

在产生State类对象时,可以传入Context对象,并将其指定给State类的成员mContext,让State
类在后续操作中,可以获取Context对象的信息或操作Context对象。定义Handle抽象方法,让继承的子类可以重新定义该方法,来呈现不同的状态行为。

//状态A
public class ConcreteStateA : State
{
    public ConcreteStateA(Context theContext) : base(theContext){}
    public override void Handle(int value)
    {
        Debug.Log("ContextStateA.Handle");
        if (value > 10)
            mContext.SetState(new ConcreteStateB(mContext));
    }
}

//状态B
public class ConcreteStateB : State
{
    public ConcreteStateB(Context theContext) : base(theContext) { }
    public override void Handle(int value)
    {
        Debug.Log("ContextStateB.Handle");
        if (value > 15)
            mContext.SetState(new ConcreteStateC(mContext));
    }
}

//状态C
public class ConcreteStateC : State
{
    public ConcreteStateC(Context theContext) : base(theContext) { }
    public override void Handle(int value)
    {
        Debug.Log("ContextStateC.Handle");
        if (value > 20)
            mContext.SetState(new ConcreteStateA(mContext));
    }
}

上述3个子类,都要重新定义父类Sate的Handle抽象方法,用来表示各自状态下的行为。在范例
中,他们各自显示不同的信息(代表当前状态的行为),再按照本身状态的行为定义来判断是否要通知Context对象转换到另一种状态。

Context提供了SetState方法让外界能够设置Context对象的当前状态,这里这个方法由State状态
来调用,所以状态的转换有俩种实现方式:

  • 交由Context类本身,按条件在各状态之间转换;
  • 产生Context对象时,马上指定初始状态给Context对象,而在后续执行过程中的状态转换则交
    由State对象负责,Context对象不再介入。

推介使用第二种方式,状态对象本身比较清楚在什么条件下,可以让Context对象转移到另一个
State状态。所以在每一个ConcreteState类中都可以看到状态转换条件的判断,以及设置哪一个ConcreteState对象成为新状态。

每个Concrete状态都可以保持自己的属性值,作为状态转换或展现状态行为的依据,不会与其他
的ConcreteState状态混用,在维护时比较容易理解。

因为判断条件机状态属性都被装换到ConcreteState类中,故而可以缩减Context类的大小。

2.外观模式(Facade)


解释:为子系统定义一组统一的接口,这个高级的接口会让子系统更容易被使用。
结构图
在这里插入图片描述

  • client(客户端、用户)
    从原本需要操作多个子系统的情况,改为只需要面对一个整合后的界面。
  • subSystem(子系统)
    原本会由不同的客户端(非同一系统相关)来操作,改为只会由内部系统之间交互使用。
  • Faccad(统一对外的界面)
    整合所有子系统的接口及功能,并提供高级界面(或接口)供客户端使用。
    接收客户端消息后,将信息传送给子系统。

优点

  • 节省时间
  • 减少系统重新编译的时间。
  • 易于分工开发
    对于一个即庞大又复杂的子系统而言,若应用外观模式,即可成为另一个Facade接口。所以,在在工作的分工配合上,开发者只需要了解对方负责系统的Facade接口类,不必深入了解其中的运行方式。
  • 增加系统的安全性
    隔离客户端对子系统的接触,除了能减少耦合度之外,还能降低系统出错概率。有时候子系统之间的沟通和构建在程序上会有一定的步骤,错误的步骤会让子系统初始化失败导致系统错误,所以像这样程序构建顺序,应该有Facade接口类来完成。

3.单例模式(Singleton)

解释:确认类只有一个对象,并提供一个全局的方法来获取这个对象。
结构图
在这里插入图片描述

  • Singleton
    能产生唯一对象的类,并提供“全局方法”让外界可以方便获取唯一的对象。
    通常会把唯一的类对象设置为“静态类属性”。

实现范例

public class Singleton
{
    private static Singleton _instance;
    public static Singleton Instance
    {
        get
        {
            if (_instance == null)
            {
                _instance = new Singleton();
            }
            return _instance;
        }
    }
    private Singleton(){}

    public string Name = "SingletonName";
}

构造器声明为私有成员,让其无法被外界访问。一般来说,有了这个声明就可以确保该类只能
产生一个对象,因为构造器是私有成员无法调用,因此可以防止其他客户端有意无意New该类对象。

4.中介者模式(Mediator)


解释:定义一个接口用来封装一群对象的互动行为。中介者通过移除对象之间的引用,来减少他们之 间的耦合度,并且能改变他们之间的互动独立性。
结构图
在这里插入图片描述

  • Colleague(同事接口)
    拥有一个Mediator属性成员,可以通过它来调用中介者的功能。
  • ConcreteColleagueX(同事接口实现类)
    实现Colleague界面的类,对于单一实现类而言,只会依赖一个Mediator接口。
  • Mediator(中介者接口)、ConcreteMediator(中介者接口实现类)
    由Mediator定义让Colleague类操作的接口。
    ConcreteMediator实现类中包含所有ConcreteColleague的对象引用。
    ConcreteColleague类之间的互动会在ConcreteMediator中发生。

实现范例

  • 用来管理Colleague对象的接口:
public abstract class Mediator
{
    public abstract void SendMessage(Colleague theColleague, string Message);
}

Mediator定义了一个抽象方法SendMessage(),主要用于外界传递信息给Colleague。

  • Mediator所管控的Colleague:
public abstract class Colleague
{
    protected Mediator m_Mediator = null;//通过Mediator对外界沟通
    public Colleague(Mediator theMediator)
    {
        m_Mediator = theMediator;
    }
    //Mediator通知请求
    public abstract void Request(string Message);
}

Colleague为抽象类,拥有一个类型为Mediator的属性成员m_Mediator,用来指向中介者,而这
个中介者会在构造器中被指定。

  • Colleague的俩个实现类
using UnityEngine;

public class ConcreteColleague1 : Colleague
{
    public ConcreteColleague1(Mediator theMediator) : base(theMediator) { }

    //执行动作
    public void Action()
    {
        //执行后需要通知其他Colleague
        m_Mediator.SendMessage(this, "Colleague1 发出通知");
    }
    //Mediator通知请求
    public override void Request(string Message)
    {
        Debug.Log("ConcreteColleague1.Request:" + Message);
    }
}
public class ConcreteColleague2 : Colleague
{
    public ConcreteColleague2(Mediator theMediator) : base(theMediator) { }
    public void Action()
    {
        m_Mediator.SendMessage(this, "Colleague2 发出通知");
    }
    public override void Request(string Message)
    {
        Debug.Log("ConcreteColleague2.Request:" + Message);
    }
}

每一个继承至Colleague的类,需要对外界沟通时,都会通过m_Mediator来传递信息。而来自
Mediator的请求也会通过父类的抽象方法Request()来进行通知。

  • Mediator的实现类:
public class ConcreteMediator : Mediator
{
    ConcreteColleague1 m_Colleague1 = null;
    ConcreteColleague2 m_Colleague2 = null;
    public void SetColleague1(ConcreteColleague1 theColleague)
    {
        m_Colleague1 = theColleague;
    }
    public void SetColleague2(ConcreteColleague2 theColleague)
    {
        m_Colleague2 = theColleague;
    }
    public override void SendMessage(Colleague theColleague, string Message)
    {
        //收到ConcreteColleague1通知ConcreteColleague2
        if (theColleague==m_Colleague1)
            m_Colleague2.Request(Message);
            //收到ConcreteColleague2通知ConcreteColleague1
        if (theColleague==m_Colleague2)
            m_Colleague1.Request(Message);
    }
}

该类拥有所有“要在内部进行沟通的Colleague子类的引用”。因为测试程序只实现俩个子类,所以
在SendMessage中只是进行简单的判断,然后就转发给另一个Colleague。

  • 测试脚本:
  private static void MenuClicked()
    {
        //产生中介者
        ConcreteMediator m_Mediator = new ConcreteMediator();
        //产生俩个Colleague
        ConcreteColleague1 m_Colleague1 = new ConcreteColleague1(m_Mediator);
        ConcreteColleague2 m_Colleague2 = new ConcreteColleague2(m_Mediator);
        //设置给中介者
        m_Mediator.SetColleague1(m_Colleague1);
        m_Mediator.SetColleague2(m_Colleague2);
        //执行
        m_Colleague1.Action();
        m_Colleague2.Action();
    }

优点
每个类对外的访问都通过中介者类对象(ConcreteMediator )来完成,这使得每一个类对外的依
赖度缩小到只有一个类(ConcreteMediator ),当系统有所变更时,受影响的仅仅局限与ConcreteMediator 类,因此可以减少系统维护难度。

5.桥接模式(Birdge)


解释:将抽象与实现分离,使二者可以独立变化。
结构图
在这里插入图片描述

  • Abstraction(抽象体接口)
    拥有指向Implementor的对象引用。
    定义抽象功能的接口,也可做为子类调用实现功能的接口。
  • RefinedAbstraction(抽象体实现、扩充)
    继承抽象体并调用Implementor完成实现功能。
    扩充抽象体的接口,增加额外的功能。
  • Implementor(实现体接口)
    定义实现功能的接口,提供给Abstraction(抽象体)使用。
    接口功能可以只有单一的功能,真正的选择则再由Abstraction(抽象体)的需求加以组合应用。
  • creteImplementorA/B(实现体)
    实际完成实现体接口上所定义的方法。

实现范例

using System;
using UnityEngine;
public abstract class RenderEngine 
{
    public abstract void Render(string ObjName);
}

public class DirectX : RenderEngine
{
    public override void Render(string ObjName)
    {
        DXRender(ObjName);
    }
    private void DXRender(string ObjName)
    {
        Debug.Log("DXRender: "+ObjName);
    }
}

public class OpenGl : RenderEngine
{
    public override void Render(string ObjName)
    {
        OpenGlRender(ObjName);
    }

    private void OpenGlRender(string ObjName)
    {
        Debug.Log("OpenGlRender: "+ObjName);
    }
}

将绘图引擎定义为RenderEngine后,再分别继承出俩个子类:DirectX和OpenGL。在俩个子类
中将父类定义的接口功能重新实现,然后在IShaper类中增加一个RenderEngine的类成员,并提供一个SetRenderEngine方法,让系统能指定当前使用的绘图引擎:

using UnityEngine;

public abstract class IShape
{
    protected RenderEngine m_RenderEngine = null;
    public void SetRenderEngine(RenderEngine theRenderEngine)
    {
        m_RenderEngine = theRenderEngine;
    }
    public abstract void Draw();
}

抽象体接口定义后,其下所有的子类都可以通过m_RenderEngine对象来调用当前指定的绘图引
擎:

public class Sphere : IShape
{
    public override void Draw()
    {
        m_RenderEngine.Render("Sphere");
    }
}

public class Cube : IShape
{
    public override void Draw()
    {
        m_RenderEngine.Render("Cube");
    }
}

public class Cyclinder : IShape
{
    public override void Draw()
    {
        m_RenderEngine.Render("Cyclinder");
    }
}
  • 测试脚本:
private static void MenuClicked()
{
    Sphere m_Sphere = new Sphere();
    //设置渲染引擎
    m_Sphere.SetRenderEngine(new OpenGl());
    //渲染
    m_Sphere.Draw();
    
    m_Sphere.SetRenderEngine(new DirectX());
    m_Sphere.Draw();
}

优点
运用桥接模式(Bridge)后的IShape(图形接口),他定义了“渲染”的功能,但真正实现“渲染”功
能的类,则是RenderEngine(渲染器接口)的实现类。对于IShape及其继承类都不必理会RenderEngine群组的变化,即使后期添加其他渲染器,对于IShape来说,他面对的只有RenderEngine这个接口类,相对的,RenderEngine类群组也不必理会IShape群组内的新增或修改,让俩个群组之间的耦合度降到最低。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值