读一读

状态抽象类IState

namespace StateNameSpace { 

    public abstract class IState  {

        public StateContext mContext;

        public IState(StateContext context)
        {
            mContext = context;
        }

        public abstract void Handle(object data);
	
    }

}

环境类Context

using System;

namespace StateNameSpace { 

    public class StateContext  {

        private IState currentState;

        private Dictionary<string, IState> stateDic = new Dictionary<string, IState>();

        public StateContext(TextAsset textAsset,string defaultState)
        {
            //解析配置,初始化状态
            string txt = textAsset.text;
            string[] lines = txt.Split('\n');
            Assembly assembly = Assembly.Load("Assembly-CSharp");
            object[] par = new object[1];
            par[0] = this;
            foreach (string str in lines)
            {
                string[] keyVal = str.Split(',');
                try
                {

                    //获取实例,CreateInstance表示使用构造方法,par是参数,其他未知
                    IState state = (IState)assembly.CreateInstance("StateNameSpace." + keyVal[1].Trim(), false, System.Reflection.BindingFlags.CreateInstance, null, par, null, null);
                    if (state == null)
                    {
                        throw new Exception("你的类名可能写错啦");
                    }

                    this.RegistState(keyVal[0], state);
                }
                catch (Exception e)
                {
                    Debug.LogError(e.Message);
                }

            }

            //设置默认状态
            SetState(defaultState);
        }

        public void Handle(object data)
        {
            if (currentState != null)
            {
                currentState.Handle(data);
            }
        }

        public void SetState(string key)
        {
            if (!isExistState(key)) return;

            IState state;
            stateDic.TryGetValue(key,out state);
            currentState = state;

        }

        public void RegistState(string key,IState state)
        {
            if (isExistState(key)) return;

            stateDic.Add(key, state);
        }

        public void RemoveState(string key)
        {
            if (!isExistState(key)) return; 
        }

        public bool isExistState(string key)
        {
            IState state;
            stateDic.TryGetValue(key, out state);

            if (state == null) {
                return false;
            }

            return true;
        }

    }

}


创建环境类,需要提供一个配置文件,告诉key对应的状态类,自动初始化和实例化具体的状态类(利用反射),保存在字典中,根据key值来获取切换状态。(状态模式使用示例


就是要对象之间要减少耦合,知道依赖的东西越少越好。低耦合,高内聚。尽量的减少对象对依赖的数量和质量,这里说的质量其实是依赖方public出来的东西。

例如,我有一个功能需要3个类来协调完成,所以我依赖上了这3个类,当功能改变时,有可能就会牵动这3个类的改变。如果我增加一个中间类,依赖上3个类,通过这个中间类来提供一个接口来实现功能,调用类也不知道里面实现了什么,此时如果功能改变,我就可以新增加一个中间类来去实现方法,然后替换调原来的,来改变原来的实现。


就是通过抽象和实现的方式来作为某个整体的部分组件,而不是依靠继承来获得某个功能,减少类和类的耦合。

比如说,鸟类都会飞,如果做出一个父类有一个飞的方法,具体鸟类去继承获得这个飞的方法,此时具体鸟类和父类就耦合在一起了,当具体鸟类的飞行方法改变,此时就需要重写父类方法或则修改父类方法,这就不符合里氏替换原则和开闭原则了。

如果通过抽象一个飞行类,让鸟类依赖这个抽象类,我们通过将实现飞行类以注入或则其他方式提供给鸟类,鸟类就有这个功能了。当飞行方法改变,就可以修改注入的飞行实现类就可以了。


接口隔离原则其实和单一原则那样,只有保证了接口隔离原则才能从根源上就保证实现类的单一职责。如果接口的方法很杂乱,一个实现类要去实现它,本来这个类实际只需要一个方法,但是这个接口是很杂乱的,有其他类型的接口方法,这个实现类还要去实现这个不需要的方法,所以,这些接口应该要细化,实现类只挑需要的接口来实现。


就是一个类,它所负责的东西要单一,要同一类型,同一种.....反正这单一的界限个人来讲还是有差异的,从而达到只有一个原因来引起这个类的改动。

例如一个加法类:

class Add : ICal{
    public int Cal(int a, int b)
    {
        return a + b;
    }
}

里面就只有一个加法运算的方法,唯一能引起这个类改动的就是加法不是这么算了,世界改变,加法用的运算符是:- ,这时候就要修改+号为-了。


就是子类不应该重写可以实例化的父类的方法,然后通过扩展子类的方法来实现新的功能,再替换掉父类,这样就可以保证原有功能的不变,同时也赋予父类(被替换掉的子类)拥有了新的功能。

符合父类可以被子类替换,且程序的逻辑不变,这就是里氏替换原则了。

如果父类是一个抽象接口,不可以实现的,里面没有逻辑性的东西,然后子类就不用担心重写(也不叫重写,叫实现了)父类方法后而改变程序逻辑了,且实现(子)类都可以替换父类,这也是符合里氏替换原则的。


就是高层模块不应该依赖于底层模块。所谓的高层模块就是调用一些类来实现某种功能的,低层模块就是那些被高层模块调用的。高层模块又要使用低层模块实现功能又不能依赖与低层模块,所以要使用接口来替代这个低层模块,从而依赖接口。

高层模块依赖于接口之后,就只需要针对接口的调用了,接口的引用的具体实现就交由配置或则第三方管理,从而方便扩展和修改。

如果高层模块依赖于低层模块,突然需求有变,不适用这个低层模块了,从而修改增加一个新的低层模块,但是高层模块用的是以前的低层模块,那么这些高层模块的代码都需要更改!如果有很多高层模块引用了这个低层模块,那么就是动一处而动全身了。


就是对扩展开放,对修改关闭。当应用需求改变时,不应该就修改原来的代码,而应该通过增加扩展的方式来完成对需求的改变。

对应的代码技术就是接口类型的,通过增加类来实现接口完成不同需求的实现。


例如:一个做一个运算类

//运算方法接口
interface ICal
{
    int Cal(int a, int b);
}
//运算加法类
class Add : ICal
{
    public int Cal(int a, int b)
    {
        return a + b;
    }
}
//运算类
class Cal
{
    //默认使用加法
    private ICal calCode = new Add();

    //用来设置使用的运算方式
    public void SetCalCode(ICal code)
    {
        calCode = code;
    }

    public int DoCal(int a, int b)
    {
        return calCode.Cal(a, b);
    }
}

这里默认使用的是加法,如果此时需要使用的是乘法,此时不应该对原来代码进行修改,而是进行扩展

//新加乘法运算类
class Mul : ICal
{
    public int Cal(int a, int b)
    {
        return a * b;
    }
}

客户端(通过某种方式,配置,注入等)切换运算类

class Program
{
    static void Main(string[] args)
    {
        Cal cal = new Cal();
        int r1 = cal.DoCal(10, 20);
        Console.WriteLine(r1);//30

        //这里只是示范,应该在第三方地方设置的,然后客户端类就不需要做任何改动了
        cal.SetCalCode(new Mul());
        int r2 = cal.DoCal(10, 20);
        Console.WriteLine(r2);//200

        Console.ReadKey();
    }
}

将请求处理,沿着链传递下去,直到有权处理的节点。(职责链模式实例

2544fc0316510f6f275eb1de54aeba76.jpg


当需要撤销恢复操作时,考虑命令模式(命令模式实例

d64e7e996f537febcad0a586fdd7d4fc.jpg