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群组内的新增或修改,让俩个群组之间的耦合度降到最低。