抽象工厂模式(Abstract Factory Pattern)是围绕一个超级工厂创建其他工厂。该超级工厂又称为其他工厂的工厂。这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。
在抽象工厂模式中,接口是负责创建一个相关对象的工厂,不需要显式指定它们的类。每个生成的工厂都能按照工厂模式提供对象。
简单的来说,就是套娃。超级工厂生产普通工厂,普通工厂生产产品。
抽象工厂模式是工厂模式的升级版
关于工厂模式可以看看我的上一篇文章:浅谈设计模式和其Unity中的应用:二、工厂模式
先理解抽象工厂模式:超级工厂生产普通工厂,普通工厂生产产品。
那我们就在工厂模式的基础上再建一个工厂模式就行了。
这里以我上一篇文章为例子。
此时多一个条件,不仅有生产电脑的工厂,还有生产手机的工厂。
首先应该有一个电脑和手机接口
public interface Computer {
void Func();
}
public interface Phone {
void Func();
}
然后有具体的电脑和手机,创建实现接口的实体类。
public class Dell : Computer {
public override void Func()
{
}
}
public class ASUS: Computer {
public override void Func()
{
}
}
public class Acer: Computer {
public override void Func()
{
}
}
public class OPPO : Phone {
public override void Func()
{
}
}
public class VIVO: Phone {
public override void Func()
{
}
}
为电脑和手机工厂创建抽象超级工厂类
public abstract class BaseFactory
{
public abstract Computer GetComputer(string produceName);
public abstract Phone GetPhone(string produceName);
}
创建一个电脑和手机工厂,生成基于给定信息的实体类的对象。
public class ComputerFactory : BaseFactory
{
//使用 GetComputer方法获取电脑类型的对象
public override Computer GetComputer(string computerName)
{
if(computerName == null)
{
result = null;
}
Computer result = null;
switch(computerName)
{
case: "Dell":
result = new Dell();
break;
case: "ASUS":
result = new ASUS();
break;
case: "Acer":
result = new Acer();
break;
default:
result = null;
break;
}
return result;
}
public override Phone GetPhone(string phoneName)
{
return null;
}
}
public class PhoneFactory : BaseFactory
{
//使用 GetPhone方法获取手机类型的对象
public Phone GetPhone(string phoneName)
{
Phone result = null;
if(phoneName== null)
{
result = null;
}
switch(phoneName)
{
case: "OPPO":
result = new OPPO();
break;
case: "VIVO":
result = new VIVO();
break;
default:
result = null;
break;
}
return result;
}
public override Computer GetComputer(string computerName)
{
return null;
}
}
创建一个工厂创造器/生成器类,通过传递工厂信息来获取工厂。
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public enum FactoryType
{
ComputerFactory,
PhoneFactory
}
public class FactoryProducer
{
public static BaseFactory GetFactory(FactoryType factoryType)
{
BaseFactory factory = null;
switch (factoryType)
{
case FactoryType.ComputerFactory:
factory = new ComputerFactory();
break;
case FactoryType.PhoneFactory:
factory = new PhoneFactory();
break;
default:
factory = null;
break;
}
return factory;
}
}
使用 FactoryProducer 来获取 BaseFactory,通过传递类型信息来获取实体类的对象。
public class AbstractFactoryPatternDemo
{
public static void Main(String[] args) {
//获取电脑工厂
BaseFactory computerFactory = FactoryProducer.GetFactory(FactoryType.ComputerFactory);
//获取 Dell 的对象,并调用它的 Func 方法
Computer dell = computerFactory.GetComputer("Dell");
//调用 Dell 的 Func方法
dell.Func();
//...
//DoSomethings
}
}
注 意 : 此 处 代 码 会 有 点 问 题 , 请 大 家 在 看 到 时 候 仔 细 思 考 , 我 会 把 问 题 和 解 决 方 案 放 在 下 方 。 \color{#0000FF}{注意:此处代码会有点问题,请大家在看到时候仔细思考,我会把问题和解决方案放在下方。} 注意:此处代码会有点问题,请大家在看到时候仔细思考,我会把问题和解决方案放在下方。
本应用是上一篇文章工厂模式的升级版,只是把工厂模式改为了抽象工厂模式。
条件增加:不止子弹这一个工厂,还有投掷物这个工厂。
相对于上一篇文章的重复步骤我就用不写了或者用文字简单说了。
建立子弹实体类:BulletController和投掷物实体类:MissileController。
建立一个抽象的超级工厂类。
注意,此时BaseFactory继承自单例类Singleton
public abstract class BaseFactory : Singleton<BaseFactory>
{
public abstract Component Creat(string produceName);
public abstract Component Creat(string produceName, Vector3 position, Quaternion rotation);
public abstract void RecoveryGameObjectToPool(string produceName, Component go);
}
创建子弹工厂和投掷物工厂。
public class BulletFactory : BaseFactory
public class MissileFactory : BaseFactory
创建一个工厂创造器/生成器类,通过传递工厂信息来获取工厂。
public enum FactoryType
{
BulletFactory,
MissileFactory
}
public class FactoryProducer
{
public static BaseFactory GetFactory(FactoryType factoryType)
{
BaseFactory factory = null;
switch (factoryType)
{
case FactoryType.BulletFactory:
factory = BulletFactory.Ins;
break;
case FactoryType.MissileFactory:
factory = MissileFactory.Ins;
break;
default:
break;
}
return factory;
}
}
假设我们玩家点击屏幕,枪械应该要射出子弹。
那么我们就这样:
public void Shoot(string bulletName)
{
Component bullet = FactoryProducer.GetFactory(FactoryType.BulletFactory).Creat(bulletName);
//让子弹开始移动
bullet.GetComponent<BulletController>().StartMove();
}
上述Unity应用在我运行的时候发生了点小错误。
为了记录下这次错误,我打算保留上述错误留下我的解决方案。
问题:由于我的BaseFactory继承自单例类,所以按道理我的BaseFactory应该只有一个子类实例,但是我的需求是BaseFactory应该是一个抽象工厂类,它有很多子类继承它,比如子弹工厂、投掷物工厂。但是实际情况是它的所有的子类就只有一个实例(原因在下方),我的单例类代码如下:
public class Singleton<T> : MonoBehaviour where T : Singleton<T>
{
private static T _ins;
public static T Ins { get { return _ins; } }
protected virtual void Awake()
{
if(_ins == null)
{
_ins = (T)this;
}
}
protected virtual void OnDestroy()
{
_ins = null;
}
public static bool IsInitialized
{
get { return _ins != null; }
}
}
其中最重要的就是
protected virtual void Awake()
{
if(_ins == null)
{
_ins = (T)this;
}
}
假设我的子弹工厂先调用Awake方法,然后我的投掷物工厂再调用Awake方法,发现_ins已经不为null了(因为他们都调用的BaseFactory的Awake,自然_ins就是第一次调用者:子弹工厂的实例,由于if条件,第一次调用已经初始化了,所以第二次就会越过)。所以我们所有的工厂都是子弹工厂了,即使你这样:MissileFactory.Ins,调用的依然是父类BaseFactory的Ins也就是子弹工厂。
我们可以让所有的工厂都继承自单例类,那么我们所有的工厂都有自己的实例,但是C#是单继承的,我们又要继承单例类,又要继承BaseFactory,这怎么办。
那我们就只好把BaseFactory写成接口了,也就是abstract class修改成interface。
修改代码如下:
public interface IBaseFactory
{
Component Creat(string produceName);
Component Creat(string produceName, Vector3 position, Quaternion rotation);
void RecoveryGameObjectToPool(string produceName, Component go);
}
public class BulletFactory : Singleton<BulletFactory>, IBaseFactory
public class MissileFactory : Singleton<MissileFactory>, IBaseFactory
下一篇文章来了解我们的状态模式和有限状态机FSM
浅谈设计模式和其Unity中的应用:四、状态模式