策略模式就是将算法抽象出来变成一个策略,方便这个算法策略的改变。缺点就是客户端必须知道哪些情况使用哪些策略。
//策略接口 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(); }
可以看出,我这里的中介者是用来做信息的沟通者的,提供给子系统添加监听和发送消息的接口。而子系统中引用这个中介者,来和其他系统沟通。(中介者模式使用示例)
外观模式是整合所有的子系统,提供出功能性的接口来统一给外界访问,减少依赖能实现这个功能的子系统。各个子系统之间没有关系,统一为外观类服务,外观类不需要给子系统服务。
中介者模式就比较惨一点了,同样是拥有很多的子系统,减少的是这些子系统之间的依赖关系,每次的交互都交给中介,中介再去找相应的目标处理,处理完了还要由中介告诉要求方完成了。中介者为所有的子系统服务,每个子系统可能是通知方,也可能是被通知方,是双向的,都是经过中介者来操作。
还有一点,外观模式是减少第三方对子系统的依赖,第三方只需要依赖外观类,就能完成需要依赖很多子系统才能完成的功能。而中介者模式是减轻各个子系统之间的依赖,例如说游戏模块战斗被攻击后,需要告诉动画模块播放受伤动画,告诉声音模块播放受伤声音,这就依赖了这两个模块,而用中介者后,只要告诉中介,受伤了,其他的就不用管了。
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"); } } }
在程序中,有很多东西在同一条件下不同状态下会出现不同的情况,就好比王者荣耀的英雄技能,比如你正在释放技能,亚瑟向你发出沉默攻击,根据你技能不同的状态来做出处理,如果是冰女的大招就被打断了,如果是安其拉的那就不会。(状态模式实例)
当然除了被攻击外,很还有其他的类容是需要这种根据不同状态发生不同事情,就是这个环境类会根据不同的状态做一系列的不同的事。而策略模式和这个的不同之处,就是策略模式是针对某一件事情,可能有很多的策略方法来解决。