面向对象设计原则
- 经常出现的问题,该问题的解决方案核心
- 软件设计过程中某一类常见问题的一般性解决方案
- 类与相互通信的对象之间的组织关系,包括他们的角色,指责,协作方式几个方面
面向对象三大机制:
封装:隐藏内部实现 通过外部接口
继承:复用现有代码
多态:改写对象行为,不同的子类在继承父类后分别都重写覆盖了父类的方法
解构,关系之间相互独立,减少互相的影响
对象是某种拥有责任的抽象
是一系列可以被其他对象使用的公共接口
对象封装了代码和数据
对类扩展而非修改
针对接口编程,只需要对象拥有需要接口
继承”白箱复用“,子类父类耦合度高
对象组合”黑箱复用“,耦合度低
单例模式
Singleton:保证一个类只有一个实例,并提供一个该实例的全局访问点,用于需要记录文件每一次修改状态的系统
- 创建型:负责对象创建 new对象
- 结构型:处理类与对象间组合
- 行为型:类与对象交互中的职责分配(组件间)
特点:
- 单例模式只在第一次被访问的时候创建,不会自主创建,内存的节约
- 只存在一个对象进行运作,不用经历对象创建和销毁,节省性能
- 可以链接游戏的各个模块,例如任何类都可以轻松调用文件系统
- 反之,促进了项目耦合,加大维护难度,难以扩展
单线程单例模式
单例模式顾名思义就是要让该类只有一个初始化的对象,首先我们需要做的是将对象的构造方法进行私有化,这样改对象就不能在外部进行实例化new,从下图可以看到当我们进行private私有化之后,在外部已经不能访问了。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| # 单线程唯一实例 public class Singleton { private static Singleton instance;
private Singleton() { }
public static Singleton Instance { get { if (instance == null) instance = new Singleton(); return instance; } } }
|
1 2 3 4 5 6 7 8 9 10 11
| class Test { public static void Main() {
Singleton t1 = Singleton.Instance; Singleton t2 = Singleton.Instance; } }
|
多线程单例模式
为什么只能在单线程中使用?我们可以看到在每次调用Instance的时候都会进行执行if (instance == null)进行判空,但是当在多线程的时候,有可能两个线程同时满足该条件,例如:在第一个线程判断为空后,还没有进行实例化,这时候第二个线程进行了判空,将进入该语句,这样的情况就会进行两次实例化。
这是一个可以多线程使用的单例模式,进行了加锁,并进行了两次判断。private static object lockHelper = new object(); 这里可以任意写一个对象,只是用于加锁使用。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| # 多线程唯一实例 public class MutiSingleton { private static volatile MutiSingleton instance = null; private static object lockHelper = new object(); private MutiSingleton() { } public static MutiSingleton Instance { get { if (lockHelper == null) { lock(lockHelper) { if (instance == null) { instance = new MutiSingleton(); } } } return instance; } } }
|
From:https://blog.csdn.net/Maybe_ch/article/details/102805855
- 静态构造函数:静态字段初始化在静态字段初始化之前初始化
观察者模式
- 为对象建立“通知依赖关系”,一个对象的状态发生改变,其他依赖对象都要知道,优化依赖关系,使其稳定
高耦合情况:不断添加对象,在父类直接修改,想到哪里写哪里,修改依赖对象影响被依赖对象,依赖了具体对象
依赖倒置,面向接口编程,为了依赖关系松耦合
依赖依赖对象的接口,多个依赖对象实现的功能类似,使用一个抽象接口
定义一个接口
两个功能(类)都使用这个接口,被依赖对象直接调用接口,变成弱依赖变成
会变化的功能抽出来作为类,减弱依赖,尽可能扩展而非修改

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38
|
public class userData { public int id; public string userEmail; public string userPhone; }
public class BankAccount { Emailer emailer; Mobile mobile; userData data;
public void WithDraw(int id) { emailer.SendEmail(data.userEmail); mobile.SendNotification(data.userPhone); } }
public class Emailer { public void SendEmail(string address) { } }
public class Mobile { public void SendNotification(string phone) { } }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71
| public class UserAccountArgs { public string ToAddress; public string MobileNumber; }
public class ArrayList<T> { void Add(T x) { } void Remove(T x) { } }
public abstract class Subject { List<IAccountObserver> observerList = new List<IAccountObserver>();
protected virtual void Notify(UserAccountArgs args) { foreach (IAccountObserver observer in observerList) observer.Updata(args); } public void AddObserver(IAccountObserver observer) { observerList.Add(observer); }
public void Remove(IAccountObserver observer) { observerList.Remove(observer); } }
public class BankAccount:Subject { public void WithDraw(int data) { UserAccountArgs args = new UserAccountArgs(); Notify(args); } }
public interface IAccountObserver { void Updata(UserAccountArgs args); }
public class Emailer: IAccountObserver { public void Updata(UserAccountArgs args) { string toAddress = args.ToAddress; } }
public class Mobile: IAccountObserver { public void Updata(UserAccountArgs args) { string mobileNumber = args.MobileNumber; } }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| public delegate void AccountChangeEventHandle(object sender, AccountChangeEventHandleArgs args);
public class BankAccount : Subject { public event AccountChangeEventHandle AccountChange; public void WithDraw(int data) { UserAccountArgs args = new UserAccountArgs(); Notify(args); } protected virtual void OnAccountChange(AccountChangeEventHandleArgs arg) { if (AccountChange != null) AccountChang(args); } }
|
From:C#设计模式合集
命令模式
- 命令类封装了执行者和方法等等各种属性,一个命令类封一种命令
- 命令列表(接收器)存储需要执行的命令,可以add,有执行方法
- 使用时 实例化命令类
- 实例后add,用接收器实例执行,add一个命令就执行一次这个命令请求
- 特点是随时发出命令,不用管谁执行,执行具体参数
命令模式:通过将命令封装成对象,实现解耦,可改变命令对象,撤销功能
readonly
:只读
eg:实现按下按键物体前后左右移动时,if(按键) 执行(移动),二者耦合,使用命令模式封装移动
1 2 3 4 5 6 7
| # Command public abstract class Command { public abstract void Execute(GameObject player); public abstract void Undo(); }
|
- 将位移通过commend封装为类,这里封装了执行对象,独立命令,撤销
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| # MoveCommand public class MoveForward :Command { private GameObject _player; public override void Execute(GameObject player) { _player = player; _player.transform.Translate(Vector3.forward); } public override void Undo() { _player.transform.Translate(Vector3.back); } }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
| public class CommandManager : MonoBehaviour { public static CommandManager Instance; private readonly List<Command> commendList = new List<Command>();
private void Awake() { if (Instance) Destroy(Instance); else Instance = this; }
public void Addcommand(Command command) { CommandList.Add(command); }
public IEnumerator Undo() { commendList.Reverse(); foreach (Command command in commandList) { yield return new WaitForSeconds(.2f); command.Undo(); } commandList.Clear(); } }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34
| public class InputHandle : MonoBehaviour { private readonly MoveForward moveForward = new MoveForward(); private readonly MoveLeft moveLeft = new MoveLeft(); private readonly MoveRight moveRight = new MoveRight(); private readonly MoveBack moveBack = new MoveBack();
private GameObject _player;
void Start() { _player = GameObject.Find("Cube"); }
void Update() { PlayerInputHandle(); }
private void PlayerInputHandle() { if (Input.GetKeyDown(KeyCode.W) { moveForward.Execute(_player); CommandManager.Instance.Addcommand(moveForward); } if (Input.GetKeyDown(KeyCode.B) { StartCoroutine(CommandManager.Instance.Undo()); } } }
|
From:【游戏开发设计模式】命令模式轻松实现撤销功能,解耦以及控制对象的可参数化
对象池模式
对象池:预先定义一个包含可重用对象的池子,初始化就创建好对象并设置为非激活状态,
当创建物体时激活池子里的对象:gameObject.setActive(true)
当销毁物体时就将物体的状态设置为非激活:gameObject.setActive(false)
ObjectPool Unity自己的对象池 set clear add remove,建字典当池子也可列表
对比于创建Instantiate(GameObject)
和销毁Destroy(GameObject)
,性能有了极大提升
对象池(线程池)一次性创建完毕,完整的分配内存,计算量小
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57
| public class Subpool { public List<GameObject> subPool = new List<GameObject>(); GameObject prefab;
public Subpool(GameObject pref) { prefab = pref; }
public GameObject OutPool() { GameObject obj = null; foreach (GameObject _obj in subPool) { if (_obj.activeSelf == false) obj = _obj; } if (obj == null) { obj = GameObject.Instantiate(prefab); subPool.Add(obj); }
obj.SetActive(true); return obj; }
public void InPool() { if (subPool.Count > 0) { foreach(GameObject _obj in subPool) { if (_obj.activeSelf == true) { _obj.SetActive(false); break; } } } }
public void InputAllObject() { foreach(GameObject _obj in subPool) { if (_obj.activeSelf == true) InPool(); } } }
|
- 父池子管理所有子池子,父池子为字典,记录自池子的名字和池子类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
| public class ObjManager { private Dictionary<string, Subpool> PoolDic = new Dictionary<string, Subpool>();
public GameObject OutPool(string name) { if (PoolDic.ContainsKey(name) == false) { GameObject obj = Resources.Load("Prefabs/" + name) as GameObject; Subpool _subpool = new Subpool(obj); PoolDic.Add(name, _subpool); } Subpool subpool = PoolDic[name]; return subpool.OutPool(); }
public void InputPool(string objname) { PoolDic[objname].InPool(); } public void InputAllObject() { foreach (Subpool sp in PoolDic.Values) sp.InputAllObject(); } }
|
From:Unity之设计模式:单例模式和对象池模式
From:https://shusheng007.top/2021/09/08/command-pattern/
https://github.com/shusheng007/design-patterns
工厂模式
- 抽象产品类—-实现产品类
- 抽象流水线类(执行方法)接口—-实现不同产品的不同执行方法,生成对应产品
- 实现:想要哪种产品实例就实例化某种执行方法———同一类型的对象用同一种接口,每加一种产品就加一个实现接口的工厂类
抽象工厂
- 抽象产品类—-实现产品类
- 抽象流水线类(执行方法)接口—-实现不同产品的不同执行方法,生成对应产品,每个工厂可能生产n种产品
- 实例化某种执行方法—产生对应产品
策略模式
- 一个操作有好多种实现方法,而你需要根据不同的情况使用if-else等分支结构来确定使用哪种实现方式的时候
- 算法的同一操作(参数,返回一样)
- 算法拆开,一个算法一个类,各个封装,相互独立