状态模式
“将多变的行为分离出来封装成状态,通过状态切换来改变呈现的行为。”
成员:
Context(状态拥有者,可以是任何有多种状态的类)、IState(状态接口)、State(状态类)
使用方法概述:
Context拥有IState状态接口对象m_State,指示当前状态。调用Context相关方法时调用m_State对应的方法呈现出不同行为,同时提供SetState方法修改当前状态。State要实现IState中会被Context调用的方法。状态切换的时机和条件可以由Context控制,但推荐的是让State拥有Context的引用,由State控制状态切换。
状态的切换有两种方式:
1、Context来控制,亲自维护各项判断条件
2、Context设置初始状态,之后由State负责(这样可以缩减Context的职责,而且State本身比较明白该切换到哪个State。不过这样需要把Context的引用传给State。)
示例:
public class Context{
//当前状态
IState m_State;
//执行状态呈现的行为HandleX,即调用状态对象的相关函数(这里的'X'指的是可以有多种)
public void RequestX(){};
//切换状态
public void SetState(IState state){
m_State = state;
}
}
public abstract class IState{
//其拥有者,用于调用SetState切换状态
Context m_Context;
//初始化设置拥有者
public void State(Context context){
m_Context = context;
}
//用于呈现行为,由拥有者的RequestX调用
public abstract void HandleX(){}
}
应用场景和优点:
单一职责:将State转换的职责分离出Context,Context只负责拥有和修改当前State
开闭:不用修改Context,增加新的State,即可扩展Context的呈现行为
依赖倒置:Context依赖IState接口,不必在意有哪些State具体类
1、降低维护难度,方便增加行为。代替了switch语句来切换状态,更优雅,减少可能的错误。一个状态相关的行为被封装在一个类中,清晰易维护。
2、外界对Context的使用方式不变,但呈现的行为却改变了。
3、状态类复用。例如游戏场景和其对应的场景状态类可以复用到不同项目中。(想想各个大厂的游戏登陆场景)
缺点:
虽然比传统的switch实现方式更易维护,但过多的状态类也麻烦。
应用:场景切换,角色AI,服务器连接状态
外观模式
“将多个接口封装在一个统一简单接口中,使内部接口之间的互动对外隐藏”
成员:
Facade(统一外观接口),SubSystemX(各个被统一的接口)
示例:
public class Facade
{
//多个子系统
private SubSystemX;
//对外提供的接口
public functionX(){
//内部子系统协同,完成对外接口的功能
SubSystem1.functionX();
SubSystem2.functionX();
SubSystem3.functionX();
//......
}
}
应用场景和优点:
迪米特:将原本对多个子系统SubSystem的操作封装成对一个接口Facade的操作,减少了互动对象
开闭:当子系统之间的合作完成的功能需要修改,只会影响统一接口Facade。
单一职责:子系统的合作由Facade负责。
1、节省时间,简洁。原本修改一个SubSystem需要修改引用它的多个类,现在只需修改Facade。
2、减少耦合,易于分工。
3、增加安全性。确保子系统按顺序协同工作。
缺点:
Facade有太多子系统会过于庞大而难以维护。
应用:UI组件
与其他模式结合:
使用单例的Facade。SubSystem之间的协同使用中介者模式,弥补互相之间沟通过于复杂的问题。
单例模式
“使类在全局只有一个对象,并通过一个全局的方法访问”
成员:
Singleton(单例类)
使用方法概述:
将构造方法设为private,对外提供获取类的静态单例instance的方法,在该方法中唯一地产生单例。
示例:
public class SingleTon{
private static SingleTon instance;
private static object _lock = new object();
private SingleTon(){}
public static SingleTone GetInstance(){
if(instance == null){
lock(_lock){
if(instace == null){
return instance = new SingleTon();
}
}
}
}
}
应用场景和优点:
方便,省略创建对象,传参,对象和数据维持独一份,快速获取。
缺点:
违反开闭:单例对象是实现类而不是抽象类。
单例类无法被继承来实现多态,因为构造函数在内部调用,已经确定了实例化的对象。
应用:日志等工具,限制实例对象个数的类(网络连接)
中介者模式
“将多个对象之间的互相的引用改为多个对象对一个中介者的引用,由中介代替它们互动”
成员:
IMediator(中介者接口)、Mediator(中介者)、IColleague(同事接口)、Colleague(同事实现类)
使用方法概述:
Colleague拥有IMediator的对象,并通过Action调用Mediator的SendMessage发送消息。Mediator拥有多个Colleague,SendMessage执行时调用所有Colleague的Request处理消息。
示例:
public abstract class IColleague{
//拥有Mediator的引用用于在方法中调用其SendMessage发送消息给其他Colleague
protected IMediator m_Mediator;
public Colleague(IMediadtor mediator){
this.m_Mediator = mediator;
}
//用于被Mediator调用,传入消息,并执行相关操作
public abstarct void Request(string Message);
}
public abstract class IMediator{
//用于被Colleague调用传入消息,发送给所有Colleague消息,通过调用它们的Request
public abstract void SendMessage(IColleague colleague, string message);
}
应用场景和优点:
迪米特:将多个Colleague之间的互相耦合改为对一个Mediator的耦合。
1、减少了多个对象之间的互相引用,方便维护。所有对象只用引用中介者这一个对象,它们的修改只会影响到中介者。
缺点:
Mediator维护的Colleague过多。
改进:
如果是多个对象与一个对象之间的互动的话,可以使用观察者模式。也就是说中介者模式适用于多个对象之间的互动。
应用:玩家界面和游戏系统之间的互动
参考:
《设计模式与游戏完美开发》
《HeadFirst设计模式》