读一读

策略模式就是将算法抽象出来变成一个策略,方便这个算法策略的改变。缺点就是客户端必须知道哪些情况使用哪些策略。

//策略接口
public interface IStrategy  {
    int GetDamage();
}
//策略实现1
public class NormalStrategy : IStrategy
{
    public int GetDamage()
    {
        return 10;
    }
}
//策略实现2
public class DoubleStrategy : IStrategy {

    public int GetDamage()
    {
        return 2 * 10;
    }
}
//Context客户端
using UnityEngine;

public class Context : MonoBehaviour {

    private IStrategy strategy = new NormalStrategy();

    void Update()
    {
        //根据情况来使用某种策略
        if (Input.GetMouseButtonDown(0))
        {
            if (strategy.GetType() == typeof(NormalStrategy))
            {
                strategy = new DoubleStrategy();
            }
            else {
                strategy = new NormalStrategy();
            }
        }

        Debug.Log(strategy.GetDamage());
    }
}

很普遍的策略模式,比起桥接模式,策略模式还少了对使用者的抽象,只抽象了被引用的使用功能部分。


这里讲述的是一个敌人和武器的故事,敌人有很多种吧,每种敌人拿不同的武器产生的效果不一样吧。所以使用桥接模式,方便添加新的敌人,添加新的武器,也方便敌人更改正在使用的武器。

public abstract class AWeapon  {

    public abstract void Attack();

}
public abstract class AEnemy {

    private AWeapon mWeapon;

    public AEnemy(AWeapon weapon)
    {
        mWeapon = weapon;
    }

    public void SetWeapon(AWeapon weapon)
    {
        mWeapon = weapon;
    }

    public void Attack()
    {
        mWeapon.Attack();
    }

}
using UnityEngine;

public class Knife : AWeapon
{
    public override void Attack()
    {
        Debug.Log("使用刀发起攻击");
    }
}
using UnityEngine;

public class Sword : AWeapon
{
    public override void Attack()
    {
        Debug.Log("使用剑发起攻击");
    }
}
using UnityEngine;

public class testQiaojie : MonoBehaviour {
    
	void Start () {
        Sword sword = new Sword();
        FirstEnemy firstEnemy = new FirstEnemy(sword);
        firstEnemy.Attack();

        //更换武器攻击
        Knife knife = new Knife();
        firstEnemy.SetWeapon(knife);
        firstEnemy.Attack();
	}
}

这样子的话,如果需要添加新的敌人的话,只需要继承AEnemy就可以了,然后给予适合的武器,这样一个活生生的新敌人就产生了,换一换武器,然后就更牛逼了。


public class SystemMediator : Mediator {
    
}
using UnityEngine;

public class AniSystem : SubSystem
{
    public AniSystem(Mediator mediator) : base(mediator) { }

    public override void Init()
    {
        mMediator.RegistAction("hit", HitAction);
    }

    public void HitAction(object data)
    {
        Debug.Log("收到攻击。播放动画");
    }
}
using UnityEngine;

public class AudioSystem : SubSystem
{

    public AudioSystem(Mediator mediator) : base(mediator) { }

    public override void Init()
    {
        mMediator.RegistAction("hit", HitAction);
    }

    private void HitAction(object data)
    {
        Debug.Log("收到攻击,播放声音");
    }
}
public class GameSystem : SubSystem
{
    public GameSystem(Mediator mediator) : base(mediator) { }

    public override void Init()
    {
        //假装是触发消息
        mMediator.SendMes("hit", 100);
    }
}
using UnityEngine;

public class testMediator : MonoBehaviour {
    
	void Start () {
        SystemMediator ss = new SystemMediator();
        AudioSystem audioSystem = new AudioSystem(ss);
        AniSystem aniSystem = new AniSystem(ss);
        GameSystem gameSystem = new GameSystem(ss);
	}
}


是这样的,我表达的意思就是,游戏模块检测到收到攻击,就发送收到攻击的消息。发送先前,声音和动画模块都注册了这个事件的监听,然后就收到消息就会调用合适的方法。(中介者使用实例


using System.Collections.Generic;
using System;

public class Mediator  {

    private Dictionary<string, Action<object>> dict = new Dictionary<string, Action<object>>();

    //注册消息
    public void RegistAction(string mes, Action<object> action)
    {
        if (CheckAction(mes))
        {
            Action<object> a = GetAction(mes);
            a += action;//开辟新内存了,引用新的地址
            //字典中保存的是以前的引用地址,移除,重新添加
            dict.Remove(mes);
            dict.Add(mes, a);
        }
        else {
            dict.Add(mes, action);
        }
    }

    //发送消息
    public void SendMes(string mes,object par)
    {
        if (CheckAction(mes)) {
            Action<object> action;
            dict.TryGetValue(mes, out action);
            action(par);
        }
    }

    public Action<object> GetAction(string mes) {
        Action<object> action;
        dict.TryGetValue(mes, out action);
        return action;
    }

    public bool CheckAction(string mes)
    {
        Action<object> action;
        dict.TryGetValue(mes, out action);

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

        return true;
    }
	
}
public abstract class SubSystem  {

    protected Mediator mMediator;

    public SubSystem(Mediator mediator)
    {
        mMediator = mediator;
        this.Init();
    }

    public abstract void Init();
}


可以看出,我这里的中介者是用来做信息的沟通者的,提供给子系统添加监听和发送消息的接口。而子系统中引用这个中介者,来和其他系统沟通。(中介者模式使用示例


外观模式是整合所有的子系统,提供出功能性的接口来统一给外界访问,减少依赖能实现这个功能的子系统。各个子系统之间没有关系,统一为外观类服务,外观类不需要给子系统服务。

中介者模式就比较惨一点了,同样是拥有很多的子系统,减少的是这些子系统之间的依赖关系,每次的交互都交给中介,中介再去找相应的目标处理,处理完了还要由中介告诉要求方完成了。中介者为所有的子系统服务,每个子系统可能是通知方,也可能是被通知方,是双向的,都是经过中介者来操作。

还有一点,外观模式是减少第三方对子系统的依赖,第三方只需要依赖外观类,就能完成需要依赖很多子系统才能完成的功能。而中介者模式是减轻各个子系统之间的依赖,例如说游戏模块战斗被攻击后,需要告诉动画模块播放受伤动画,告诉声音模块播放受伤声音,这就依赖了这两个模块,而用中介者后,只要告诉中介,受伤了,其他的就不用管了。


中介者模式是一个为了减轻各个模块之间的依赖而产生的,它集合起所有的模块负责传达这些模块的沟通交流。(中介者模式实例

比如说,游戏模块需要播放声音,直接告诉中介,中介做什么他不管,中介当然会告诉声音模块然后播放声音了,当然了,声音模块在播放完声音后也可以告诉中介播放完了,中介在去通知谁谁谁搞事情。

687474703a2f2f6f77767365747571752e626b742e636c6f7564646e2e636f6d2f696d6167652f64657369676e7061747465726e2f6d65646961746f72332e706e67.png


public class AudioManager  {

    private static AudioManager _instance;

    private AudioManager() { }

    public static AudioManager Instance {
        get {
            if (_instance == null) {
                _instance = new AudioManager();
            }
            return _instance;
        }
    }
}

使用一个私有变量来保存唯一的实例,设置构造方法为私有的,不让外部有实例化的可能。

通过一个公开的属性来获取这个唯一的实例。


using UnityEngine;

public class TestFacade : MonoBehaviour
{

    private JiJinCompany jjCompony;

    void Awake()
    {
        jjCompony = new JiJinCompany(100000);
        InvokeRepeating("EveryDay", 0, 0.5f);
    }

    void EveryDay()
    {
        Debug.Log("今天获得收益:" + jjCompony.GetIncome());
    }

}

可以发现,客户端类(你)只需要和基金公司交互就行了,把钱给了基金公司后,每天就可以查看自己的收益,而不需要去整合一下银行的和股票的等,如果收益不满意,直接买一个地方就可以了。(外观模式实例


所谓外观类就是提供一个中间类(外观类),来降低客户和子系统的耦合,如果需求有变,换一个外观类就好了,接口不变。

举一个基金的例子,子系统是投资股票和银行...

using System;

public class YinHang {

    public int GetInCome(int money)
    {
        Random r = new Random();
        int income = money * r.Next(-10,100) / 1000;

        return income;
    }
	
}
using System;

public class GuPiao  {

    public int GetIncome(int money)
    {
        Random r = new Random();
        int income = money * r.Next(-10, 10) / 100;

        return income;
    }

}

基金公司外观类

public class JiJinCompany  {

    //将子系统整合起来
    private YinHang mYingHang;
    private GuPiao mGuPiao;
    private int mMoney;

    public JiJinCompany(int money)
    {
        mYingHang = new YinHang(); 
        mGuPiao = new GuPiao() ;
        mMoney = money;
    }

    //提供接口对外处理
    public int GetIncome()
    {
        int income = 0;
        income += mYingHang.GetInCome(mMoney);
        income += mGuPiao.GetIncome(mMoney);

        mMoney += income;

        return income;
    }

}

现在有了基金公司这个外观类,你只需要给钱它,它就会自动帮你去投资银行和股票,但是你不知道是怎么投资的。(迪米特法则)

如果是你自己去投资,你去要去银行,又要去股市,而有了外观类(基金公司),就只需要知道基金公司就行了。(外观模式使用示例


一.配置状态,txt文件

run,RunState
idel,IdelState

二.创建这两个状态类,继承IState

using UnityEngine;

namespace StateNameSpace
{
    public class IdelState : IState
    {

        public IdelState(StateContext stateContext) : base(stateContext) { }

        public override void Handle(object data)
        {
            //播放受伤动画
            Debug.Log("受到攻击");
        }
    }
}
using UnityEngine;

namespace StateNameSpace
{
    public class RunState : IState
    {

        public RunState(StateContext stateContext) : base(stateContext) { }

        public override void Handle(object data)
        {
            //跑动状态受到攻击,改变为行走状态
            mContext.SetState("idel");
            Debug.Log("遭受攻击,奔跑被打断");
            //其他处理等,吹不出来了
        }
    }
}

三.使用一下

using UnityEngine;
using StateNameSpace;

public class TestStateMode : MonoBehaviour {

    public TextAsset asset;
    private StateContext bAttackcontext;

    void Awake()
    {
        bAttackcontext = new StateContext(asset, "idel");
    }
	
	// Update is called once per frame
	void Update () {
        if (Input.GetMouseButtonDown(0))
        {
            //假如是遭受攻击
            bAttackcontext.Handle(null);
        }

        float h = Input.GetAxis("Horizontal");
        float v = Input.GetAxis("Vertical");

        if (h != 0 || v != 0)
        {
            bAttackcontext.SetState("run");
        }
        else
        {
            bAttackcontext.SetState("idel");
        }
	}
}

在程序中,有很多东西在同一条件下不同状态下会出现不同的情况,就好比王者荣耀的英雄技能,比如你正在释放技能,亚瑟向你发出沉默攻击,根据你技能不同的状态来做出处理,如果是冰女的大招就被打断了,如果是安其拉的那就不会。(状态模式实例

当然除了被攻击外,很还有其他的类容是需要这种根据不同状态发生不同事情,就是这个环境类会根据不同的状态做一系列的不同的事。而策略模式和这个的不同之处,就是策略模式是针对某一件事情,可能有很多的策略方法来解决。