策略模式就是将算法抽象出来变成一个策略,方便这个算法策略的改变。缺点就是客户端必须知道哪些情况使用哪些策略。
//策略接口
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");
}
}
}在程序中,有很多东西在同一条件下不同状态下会出现不同的情况,就好比王者荣耀的英雄技能,比如你正在释放技能,亚瑟向你发出沉默攻击,根据你技能不同的状态来做出处理,如果是冰女的大招就被打断了,如果是安其拉的那就不会。(状态模式实例)
当然除了被攻击外,很还有其他的类容是需要这种根据不同状态发生不同事情,就是这个环境类会根据不同的状态做一系列的不同的事。而策略模式和这个的不同之处,就是策略模式是针对某一件事情,可能有很多的策略方法来解决。