Unity开发常用设计模式(初级)

单例模式

单例模式比较简单

以下代码重点演示单例的会是同一个地址,返回同一个哈希值

using System.Collections;
using System.Collections.Generic;
using UnityEngine;


public class MySingleton
{
private static MySingleton instance;

public static MySingleton Instance
{
get
{
if (instance == null)
instance = new MySingleton();
return instance;
}
}

private MySingleton()
{
Debug.Log("构造函数执行");
}

public void Show()
{
Debug.Log("Show");
}

}
public class DesignPattern : MonoBehaviour
{
// Start is called before the first frame update
void Start()
{
MySingleton single1 = MySingleton.Instance;
single1.Show();
Debug.Log(single1.GetHashCode());

MySingleton single2 = MySingleton.Instance;
single2.Show();
Debug.Log(single2.GetHashCode());

MySingleton single3 = MySingleton.Instance;
single3.Show();
Debug.Log(single3.GetHashCode());
//以上这三个对象指向同一个地址
}
}

观察者模式

代码示例:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System;

//这里介绍观察者模式
//例子是:猫来了,所有的老鼠开始逃跑

public class Animal
{
protected string strName;

public Animal(string name)
{
this.strName = name;
}

public virtual void Run()
{

}
}

public class Cat: Animal
{
public Action action;//发布者
public Cat(string name):base(name)//构造函数
{
}

public void Coming(/*Animal mouseA, Animal mouseB, Animal mouseC*/)
{
Debug.Log(strName + "来了");
//mouseA.Run();
//mouseB.Run();
//mouseC.Run();
//在没有观察者模式的时候需要挨个调用

if (action != null)
action();//触发事件;通过多播委托完成一对多的关系

this.Run();
}

public override void Run()//函数的重载
{
Debug.Log(strName + "开始追");
}
}

public class Mouse: Animal
{
public Mouse(string name, Cat cat):base(name)
{
cat.action += this.Run;//订阅者
}

public override void Run()//事件处理器
{
Debug.Log( strName + "开始逃跑");
}
}

public class ObserverPattern : MonoBehaviour
{
// Start is called before the first frame update
void Start()
{
Cat cat = new Cat("小野猫");

Animal mouseA = new Mouse("mouseA", cat);
Animal mouseB = new Mouse("mouseB", cat);
Animal mouseC = new Mouse("mouseC", cat);
Animal mouseD = new Mouse("mouseD", cat);

//cat.Coming(mouseA, mouseB, mouseC);
cat.Coming();
}
}

运行结果:

Unity开发常用设计模式(初级)

以下代码展示观察者模式和非观察者模式的写法差异

//普通写法
//缺点在于如果后续需要新增相应的对象,那么每次都需要在cat的函数中手动新增响应对象
public class Cat: Animal
{
public Cat(string name):base(name)//构造函数
{
}

public void Coming(Animal mouseA, Animal mouseB, Animal mouseC)
{
Debug.Log(strName + "来了");
mouseA.Run();
mouseB.Run();
mouseC.Run();
this.Run();
}

public override void Run()//函数的重载
{
Debug.Log(strName + "开始追");
}
}

//观察者模式的写法
public class Cat: Animal
{
public Action action;
public Cat(string name):base(name)//构造函数
{
}

public void Coming(Animal mouseA, Animal mouseB, Animal mouseC)
{
Debug.Log(strName + "来了");
if(action!= null)
action();//在Mouse的构造函数中将其Run方法注册给这个cat的
this.Run();
}

public override void Run()//函数的重载
{
Debug.Log(strName + "开始追");
}
}

public class Mouse: Animal
{
public Mouse(string name, Cat cat):base(name)
{
cat.action += this.Run;//订阅者
}

public override void Run()//事件处理器
{
Debug.Log( strName + "开始逃跑");
}
}

工厂家族

简单工厂模式

关键词:创建型模式,本质上是一种静态工厂方法模式(Static Factory Method)

主要思想:

Unity开发常用设计模式(初级)

我们创建了两个脚本,包含四个类:

  • MouseProduct:父类,还有两个品牌的子类Dell和HP
  • MainFactory:一个MainFactory类+一个SimpleFactory类,SimpleFactory类在MainFactory中进行调用;其中SimpleFactory类中还用到了一个枚举

MouseProduct脚本:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

namespace MouseManufactoring
{
public abstract class MouseProduct
{
public abstract void Print();
}

public class DellMouse : MouseProduct
{
public override void Print()
{
Debug.Log("生产了一个戴尔鼠标");
}
}

public class HpMouse : MouseProduct
{
public override void Print()
{
Debug.Log("生产了一个HP鼠标");
}
}
}

MainFactory脚本:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using MouseManufactoring;

public enum MouseType { DellMouse, HpMouse,};

public class MainFactory : MonoBehaviour
{
void Start()
{
RunFactoryMode();
}

public void RunNormal()
{
DellMouse dellMouse = new DellMouse();
dellMouse.Print();

HpMouse hpMouse = new HpMouse();
hpMouse.Print();
}

public void RunFactoryMode()
{
SimpleFactory simpleFactory = new SimpleFactory();//将简单工厂实例化

simpleFactory.CreateMouse(MouseType.DellMouse).Print();
simpleFactory.CreateMouse(MouseType.HpMouse).Print();
}

}


public class SimpleFactory
{
public MouseProduct CreateMouse(MouseType type)
{
MouseProduct mouse = null;
switch (type)
{
case MouseType.DellMouse:
mouse = new DellMouse();
break;
case MouseType.HpMouse:
mouse = new HpMouse();
break;
}

return mouse;
}
}

也可以做如下改造使得可以控制生产的品牌:

public enum MouseType { DellMouse, HpMouse,};

public class MainFactory : MonoBehaviour
{
public MouseType brand;
void Start()
{
RunFactoryMode(brand);
}

public void RunNormal()
{
DellMouse dellMouse = new DellMouse();
dellMouse.Print();

HpMouse hpMouse = new HpMouse();
hpMouse.Print();
}

public void RunFactoryMode(MouseType type)
{
SimpleFactory simpleFactory = new SimpleFactory();//将简单工厂实例化

simpleFactory.CreateMouse(type).Print();
}
}

缺陷:简单工厂模式如果需要再增加一个产品,需要新建一个类、枚举,并且需要修改CreateMouse的方法,违背了开闭原则。

工厂模式

关键词:解决简单工厂模式中,新增产品品牌的时候,需要直接修改工厂类的问题。

解决了简单工厂模式中出现的开闭原则问题,一个中间件只能生产一种产品。以下展示了简单工厂和工厂模式的区别。

Unity开发常用设计模式(初级)

本次我们创建了3个脚本:

  • 产品脚本:由一个抽象类和其子类组成,子类分别代表不同的品牌,包含各自的Print函数
  • 中间件脚本:由一个抽象类和其子类组成,子类分别代表不同品牌的工厂,包含各自的生产函数
  • 主要工厂脚本:挂载在游戏物体上,在Start中调用一个运行方法

产品脚本:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

namespace FactoryPattern
{
public abstract class PorductFactoryPattern
{
public abstract void Print();
}

public class DellMouse: PorductFactoryPattern
{
public override void Print()
{
Debug.Log("生产了一个Dell鼠标");
}
}

public class HPMouse : PorductFactoryPattern
{
public override void Print()
{
Debug.Log("生产了一个HP鼠标");
}
}
}

中间件脚本:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using FactoryPattern;
public abstract class MidBase
{
public abstract PorductFactoryPattern CreateMouse();
}

public class DellFactoryMid: MidBase//Dell中间件
{
public override PorductFactoryPattern CreateMouse()
{
return new DellMouse();
}
}

public class HPFactoryMid: MidBase//HP中间件
{
public override PorductFactoryPattern CreateMouse()
{
return new HPMouse();
}
}

主要工厂脚本:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using FactoryPattern;

public class MainFactoryPattern : MonoBehaviour
{
void Start()
{
RunFactoryMode();
}

public void RunNormal()//普通模式的运行方法
{
DellMouse dellMouse = new DellMouse();
dellMouse.Print();

HPMouse hpMouse = new HPMouse();
hpMouse.Print();
}

public void RunFactoryMode(MouseType type)//简单工厂模式的运行方法
{
SimpleFactory simpleFactory = new SimpleFactory();//将简单工厂实例化

simpleFactory.CreateMouse(type).Print();
}

public void RunFactoryMode()
{
DellFactoryMid dellFactoryMid = new DellFactoryMid();
dellFactoryMid.CreateMouse().Print();

HPFactoryMid hpFactoryMid = new HPFactoryMid();
hpFactoryMid.CreateMouse().Print();
}
}

抽象工厂模式

关键词:解决生产系列产品的问题,比如我们不只是生产鼠标,我们还生产键盘

具体的脚本构成:

鼠标脚本:鼠标抽象父类+鼠标子类

键盘脚本:键盘抽象父类+键盘子类

中间件脚本:中间件抽象父类+中间件子类(生成鼠标和键盘)

主要工厂脚本:Start中调用运行方法

适配器模式(Adapter Pattern)

Unity开发常用设计模式(初级)

脚本构成:

具体数据线脚本:可以用抽象父类,也可以不用

适配器脚本:根据枚举判断不同的类型调用各自的方法

主要调用脚本:在Start中进行调用

具体数据线脚本:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

namespace AdapterPattern
{
public abstract class Lines
{
public abstract void Charge();
}

public class AndroidLine: Lines
{
public override void Charge()
{
Debug.Log("这是安卓充电线在充电中……");
}
}

public class IOSLine: Lines
{
public override void Charge()
{
Debug.Log("这是苹果充电线在充电中……");
}
}
}

适配器脚本:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using AdapterPattern;

public interface IAdapter
{
void Charge(LineType type);
}

public enum LineType { None, ios, android, };

public class Adapter: IAdapter
{
AndroidLine androidLine = new AndroidLine();
IOSLine iOSLine = new IOSLine();
public void Charge(LineType type)
{
if (type == LineType.ios)
{
iOSLine.Charge();
}
else if (type == LineType.android)
{
androidLine.Charge();
}
}
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using AdapterPattern;

public class MainAdapter : MonoBehaviour
{
public LineType type;
// Start is called before the first frame update
void Start()
{
Adapter adapter = new Adapter();
//IAdapter adapter = new Adapter();
//这里这种写法也是可以的,还没有弄懂为什么,记个Todo
adapter.Charge(type);
}
}
发表评论

相关文章