50字范文,内容丰富有趣,生活中的好帮手!
50字范文 > [读书笔记] 设计模式与游戏完美开发

[读书笔记] 设计模式与游戏完美开发

时间:2022-11-17 00:59:47

相关推荐

[读书笔记] 设计模式与游戏完美开发

最近在看《设计模式与游戏完美开发》,文章将记录一些要点和一些设计模式实现

GoF定义的23种设计模式及应用场景

系统设计可以采用的设计模式:单例、状态(场景切换)、外观(保证高内聚)、中介者(保证低解耦)角色设计可以采用的设计模式:桥接(武器、技能)、策略(属性计算)、模板方法(重复流程)、状态(AI)对象管理可以采用的设计模式:工厂(角色产生)、建造者(生产流程与功能表现分离)、享元(子弹、特效)逻辑设计可以采用的设计模式:命令(撤销回退)、责任链(关卡)辅助功能可以采用的设计模式:组合(UI、红点)、观察者(好友、成就)、备忘录(存档)、访问者(管理某一类对象)游戏优化可以采用的设计模式:装饰、适配器、代理其他模式:迭代器、原型、解释器、抽象工厂

中介者模式

关于中介者模式,我们想象在一家互联网公司,有多个Colleague(同事),Colleague(同事)之间需要合作开发,不管是采用哪种版本控制软件,都可以抽象为一个Mediator(中介者)。而每个Colleague(同事)需要有版本控制的权限,即Mediator引用,而ConcreteMediator(具体中介者)则为ConcreteColleague(具体同事)提供服务。

Mediator.cs

public abstract class Mediator{public abstract void SendMessage(Colleague theColleage, string message);}

ConcreateMediator.cs

public class ConcreateMediator : Mediator{ConcreateColleague1 m_Colleague1 = null;ConcreateColleague2 m_Colleague2 = null;public void SetColleage1(ConcreateColleague1 theColleague){m_Colleague1 = theColleague;}public void SetColleage2(ConcreateColleague2 theColleague){m_Colleague2 = theColleague;}public override void SendMessage(Colleague theColleague, string message){if (theColleague == m_Colleague1){m_Colleague2.Request(message);} else if (theColleague == m_Colleague2){m_Colleague1.Request(message);}}}

Colleage.cs

public abstract class Colleague{protected Mediator m_Mediator = null;public Colleague(Mediator mediator){m_Mediator = mediator;}public abstract void Request(string message);}

ConcreateColleage1.cs、ConcreateColleage2.cs

using UnityEngine;public class ConcreateColleague1 : Colleague{public ConcreateColleague1(Mediator mediator) : base(mediator){}public void Action(){m_Mediator.SendMessage(this, "Concreate1执行");}public override void Request(string message){Debug.Log("C2已接收:" + message);}}using UnityEngine;public class ConcreateColleague2 : Colleague{public ConcreateColleague2(Mediator mediator) : base(mediator){}public void Action(){m_Mediator.SendMessage(this, "Concreate2执行");}public override void Request(string message){Debug.Log("C2已接收:" + message);}}

Test.cs

using UnityEngine;public class Test : MonoBehaviour{void Start(){// 定义具体中介者、具体同事ConcreateMediator pMediator = new ConcreateMediator();ConcreateColleague1 pColleage1 = new ConcreateColleague1(pMediator);ConcreateColleague2 pColleage2 = new ConcreateColleague2(pMediator);// 添加同事pMediator.SetColleage1(pColleage1);pMediator.SetColleage2(pColleage2);// 同事执行行为,中介者负责派发消息pColleage1.Action();pColleage2.Action();}void Update(){}}

tips:有些情况下,Mediator会同时采用单例模式实现,在这种情况下,尽量避免从Mediator派生ConcreateMediator,这是因为当ConcreateMediator作为单例使用时,会因为单例只会存在唯一示例,当父类有多个派生类时会有“白马非马”的逻辑诡辩。同时为了遵循开闭原则,也要尽量依赖“接口”,而非依赖“实现”。

里氏替换原则有至少以下两种含义:

里氏替换原则是针对继承而言的,如果继承是为了实现代码重用,那么共享的父类方法就应该保持不变,不能被子类重新定义。 如果继承的目的是为了多态,而多态的前提就是子类覆盖并重新定义父类的方法,应该将父类定义为抽象类。不符合LSP的最常见的情况是,父类和子类都是可实例化的非抽象类,且父类的方法被子类重新定义,这一类的实现继承会造成父类和子类间的强耦合,也就是实际上并不相关的属性和方法牵强附会在一起,不利于程序扩展和维护。

工厂模式

工厂模式是最简单的一种设计模式,由ConcreteCreate(具体工厂)产生ConcreateProduct(具体产品)

Creator.cs

public abstract class Creator{public abstract Product FactoryMethod();}

ConcreateCreatorProductA.cs

using UnityEngine;public class ConcreateCreatorProductA : Creator{public ConcreateCreatorProductA(){Debug.Log("产生工厂A");}public override Product FactoryMethod(){return new ConcreateProductA();}}

Product.cs

public abstract class Product {}

ConcreateProductA

using UnityEngine;public class ConcreateProductA : Product{public ConcreateProductA(){Debug.Log("生产A");}}

tips:通过不同子类工厂产生不同品类的产品,当产品种类过多时,会导致“工厂子类暴增”。这时候可以配合FactoryMethod传参实现工厂模式

建造者模式

对于一个工厂来说,一条流水线应该可以生产多种产品吗,即生产流程与产品装配是可以解耦的。由Director(建造者指示者)对产品生产流程进行管控,而Builder(建造者)有很多ConcerteBuilder(具体建造者)则负责不同功能的装配。

Director.cs

public class Director{public Product m_Product;public Director() {}public void Construct(Builder theBuilder){m_Product = new Product();theBuilder.BuilderPart1(m_Product);theBuilder.BuilderPart2(m_Product);}public Product GetResult(){return m_Product;}}

Builder.cs

public abstract class Builder{public abstract void BuilderPart1(Product theProduct);public abstract void BuilderPart2(Product theProduct);}

ConcreateBuilderA.cs

public class ConcreateBuilderA : Builder{public override void BuilderPart1(Product theProduct){theProduct.AddPart("产品A工人:生产部件1");}public override void BuilderPart2(Product theProduct){theProduct.AddPart("产品A工人:生产部件2");}}

using UnityEngine;using System.Collections;public class ConcreateBuilderB : Builder{public override void BuilderPart1(Product theProduct){theProduct.AddPart("产品B工人:生产部件1");}public override void BuilderPart2(Product theProduct){theProduct.AddPart("产品B工人:生产部件2");}}

Product.cs

using UnityEngine;using System.Collections.Generic;public class Product{private List<string> m_Part = new List<string>();public Product() {}public void AddPart(string v){m_Part.Add(v);}public void ShowProduct(){foreach(var part in m_Part){Debug.Log(part);}}}

Test.cs

using UnityEngine;public class Test : MonoBehaviour{Director director = new Director();Product theProduct = null;void Start(){director.Construct(new ConcreateBuilderA());theProduct = director.GetResult();theProduct.ShowProduct();director.Construct(new ConcreateBuilderB());theProduct = director.GetResult();theProduct.ShowProduct();}}

享元模式

书中描述的案例,个人以为不适合理解,故此处暂留

组合模式

“将对象以树状结构进行组合,用以表现部分与整体的层次关系”,UI的层次结构正好适合使用这种设计模式。

Component(组件界面)用来定义树形结构,以及每个结点都能使用的操作,Composite(组合结点,即根结点),实现Component定义的各个方法,Leaf(叶结点,终端结点)

IComponent.cs

using UnityEngine;public abstract class IComponent{protected string m_Value;public abstract void Operation();public virtual void Add(IComponent theComponent){Debug.Log("子类未实现");}public virtual void Remove(IComponent theComponent){Debug.Log("子类未实现");}public virtual IComponent GetChild(int index){Debug.Log("子类未实现");return null;}}

Composite.cs

using UnityEngine;using System.Collections.Generic;public class Composite : IComponent{List<IComponent> m_Childs = new List<IComponent>();public Composite(string value){m_Value = value;}public override void Add(IComponent theComponent){m_Childs.Add(theComponent);}public override void Remove(IComponent theComponent){m_Childs.Remove(theComponent);}public override IComponent GetChild(int index){return m_Childs[index];}public override void Operation(){Debug.Log("根节点执行" + m_Value);foreach (IComponent theComponent in m_Childs){theComponent.Operation();}}}

Leaf.cs

using UnityEngine;public class Leaf : IComponent{public Leaf(string value){m_Value = value;}public override void Operation(){Debug.Log("叶节点执行:" + m_Value);}}

test.cs

using UnityEngine;public class Test2 : MonoBehaviour{IComponent theRoot;void Start(){theRoot = new Composite("Root");theRoot.Add(new Leaf("Leaf1"));theRoot.Add(new Leaf("Leaf2"));IComponent theChild1 = new Composite("Child1");theChild1.Add(new Leaf("child1.Leaf1"));theChild1.Add(new Leaf("child1.Leaf2"));theRoot.Add(theChild1);IComponent theChild2 = new Composite("Child1");theChild2.Add(new Leaf("child2.Leaf1"));theChild2.Add(new Leaf("child2.Leaf2"));theRoot.Add(theChild2);theRoot.Operation();}}

tips:GameObject.Find()会遍历所有场景中的对象,而且在Unity中存在重名的问题,会产生性能问题。可以通过自己实现Find,保证只在指定的Canvas下查找

UI的功能在场景初始化时决定,保证UI逻辑与表现分离

责任链模式

责任链可以理解为数据结构的链表,每个Handler都有下一个Handler的引用。在关卡系统的设计上,很多项目会采用CreateStage(创建关卡)、CheckNextStage(检查进入下一关)方法来对场景进行操作,而采用责任链模式,则可以使用Handler(关卡对象)替代,通过类化关卡数据、通关条件能够提高关卡系统的灵活度。

Handler.cs

public abstract class Handler{protected Handler m_NextHandle = null;public Handler(Handler theNextHandle){m_NextHandle = theNextHandle;}public virtual void HandleRequest(int cost){if (m_NextHandle != null){m_NextHandle.HandleRequest(cost);}}}

ConcreateHandle1.cs

using UnityEngine;public class ConcreateHandle1 : Handler{public int m_CostCheck = 10;public ConcreateHandle1(Handler theNextHandle) : base(theNextHandle) {}public override void HandleRequest(int cost){if (cost < m_CostCheck){Debug.Log("ConcreateHandle2核准");} else{base.HandleRequest(cost);}}}

ConcreateHandle2.cs

using UnityEngine;public class ConcreateHandle2 : Handler{public int m_CostCheck = 20;public ConcreateHandle2(Handler theNextHandle) : base(theNextHandle) {}public override void HandleRequest(int cost){if (cost <= m_CostCheck){Debug.Log("ConcreateHandle2核准");}else{base.HandleRequest(cost);}}}

Test.cs

using UnityEngine;using System.Collections;public class Test : MonoBehaviour{void Start(){ConcreateHandle2 theHandle2 = new ConcreateHandle2(null);ConcreateHandle1 theHandle1 = new ConcreateHandle1(theHandle2);theHandle1.HandleRequest(5);theHandle1.HandleRequest(20);}}

观察者模式

对于发布-订阅关系来说,一个Subject可以对应多个Observer,Subject维护观察者列表,并提供Notify()通知功能;Observer提供Update()方法,在Subject通知更新时调用。

Subject.cs

using System.Collections.Generic;public abstract class Subject{List<Observer> m_Observer = new List<Observer>();public void Attach(Observer theObserver){m_Observer.Add(theObserver);}public void Detach(Observer theObserver){m_Observer.Remove(theObserver);}public void Notify(){// 通知所有观察者foreach (Observer observer in m_Observer){observer.Update();}}}

ConcreateSubject.cs

using UnityEngine;using System.Collections;public class ConcreateSubject : Subject{string m_SubjectState;public void SetState(string state){m_SubjectState = state;Notify();}public string GetState(){return m_SubjectState;}}

Observer.cs

using UnityEngine;using System.Collections;public abstract class Observer{public abstract void Update();}

ConcreateObserver.cs

using UnityEngine;public class ConcreateObserver : Observer{string m_ObjectState;ConcreateSubject m_Subject = null;public ConcreateObserver(ConcreateSubject subject){m_Subject = subject;}public override void Update(){Debug.Log("ConcreteObserver.Update");Debug.Log("ConcreateObserver1:Subject" + m_ObjectState);}}

Test.cs

using UnityEngine;using System.Collections;public class Test : MonoBehaviour{ConcreateSubject theSubject = null;ConcreateObserver theObserver = null;// Use this for initializationvoid Start(){theSubject = new ConcreateSubject();theObserver = new ConcreateObserver(theSubject);theSubject.Attach(theObserver1); // 观察者参与订阅theSubject.SetState("Subject状态1"); // 主题修改状态,并通知theObserver1.ShowState(); // 观察者接收通知并执行Update()操作}}

备忘录模式

在不违反封装的原则下,获取一个对象的内部状态并保留在外部。当我们想办法去获取游戏系统的数据时,现有系统难免被改动,而如果由游戏系统主动提供数据,则可以保证系统的封装性,这也是备忘录模式的精髓。Originator(记录拥有者)会自动产出需要保存的记录Memento(记录保存者,我称之为记忆体),由Caretaker(记录看守者)维护多个Memento。

Originator.cs

using UnityEngine;public class Originator{string m_State;public void SetInfo(string state){m_State = state;}public void ShowInfo(){Debug.Log("Originator State" + m_State);}public Memento CreateMemento(){Memento newMemento = new Memento();newMemento.SetState(m_State);return newMemento;}public void SetMemento(Memento m){m_State = m.GetState();}}

Memento.cs

public class Memento{string m_State;public string GetState(){return m_State;}public void SetState(string state){m_State = state;}}

Caretaker.cs

using System.Collections.Generic;public class Caretaker{Dictionary<string, Memento> m_Mementos = new Dictionary<string, Memento>();public void AddMemento(string version, Memento theMemento){if (m_Mementos.ContainsKey(version) == false)m_Mementos.Add(version, theMemento);elsem_Mementos[version] = theMemento;}public Memento GetMemento(string version){if (m_Mementos.ContainsKey(version) == false)return null;return m_Mementos[version];}}

Test.cs

using System.Collections;public class Test : MonoBehaviour{void Start(){Originator theOriginator = new Originator();Caretaker theCaretaker = new Caretaker();theOriginator.SetInfo("version1");theOriginator.ShowInfo();theCaretaker.AddMemento("1", theOriginator.CreateMemento());theOriginator.SetInfo("version2");theOriginator.ShowInfo();theCaretaker.AddMemento("2", theOriginator.CreateMemento());theOriginator.SetInfo("version3");theOriginator.ShowInfo();theOriginator.SetMemento(theCaretaker.GetMemento("2"));theOriginator.ShowInfo();theOriginator.SetMemento(theCaretaker.GetMemento("1"));theOriginator.ShowInfo();}}

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。