3

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

 2 years ago
source link: https://blog.51cto.com/u_15639010/5625106
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

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

精选 原创

六大米nb 2022-08-26 17:04:36 博主文章分类:游戏开发笔记 ©著作权

文章标签 中间件 设计模式 unity 游戏开发 文章分类 Unity3D 游戏开发 阅读数277

单例模式比较简单

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

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开发常用设计模式(初级)_unity_02

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

  • 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开发常用设计模式(初级)_中间件_03

本次我们创建了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开发常用设计模式(初级)_unity_04

脚本构成:

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

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

主要调用脚本:在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);
}
}

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK