抽象工厂模式在unity3d里面的使用

今天咱们就要开启工厂家族里面的最后一个模式—抽象工厂模式。在修炼抽象工厂模式心法之前我先说个例子,大家都应该知道葵花宝典吧。想必你可能知道欲练此功必先自宫,哈哈!或许你看到的只是他的上半部,但当你看到下半部结尾一行醒目的文字-欲练此功也可不必自宫,此刻傻眼了吧!失去了独领风骚的快感。由此例子,来引出产品族的概念。葵花宝典的上下部产生了相互影响就可以认为是一个产品族。所谓产品族,是指位于不同产品等级结构,功能相关联的产品组成的家族。由产品族,我们来进入抽象工厂模式。抽象工厂模式是工厂方法的升级版,是所有形态的工厂模式中最为抽象和最具一般性的形态。因此所谓的抽象工厂是一个工厂等级结构可以创建分属于不同产品等级结构的一个产品族中的所有对象。说了那么多了让我们开始修炼抽象工厂模式的心法吧。

修炼抽象工厂模式的心法如下:
1)抽象工厂角色AbstractFactory:此角色是工厂方法模式的核心,与系统业务逻辑无关。
2)具体工厂角色ConcreteFactory:此角色在客户端的调用下创建产品的实例。他包含有选择合适产品对象的逻辑,而这个逻辑是与应用系统的业务逻辑紧密相关。
3)抽象产品角色AbstractProduct:担任这个角色的类是工厂方法模式所创建对象的父类或他们共同拥有的接口。
4) 具体产品角色ConcreteProduct:抽象工厂模式所创建的任何产品对象都是某一个具体产品类的实例。这是客户端最终需要的东西,里面包含了应用系统的业务逻辑。

修炼抽象工厂模式的武功套路如下:

(备注:上面是抽象工厂模式demo里面的定向关系图文档的截图!)

修炼心法与武功套路的对应:
1)        抽象工厂角色AbstractFactory对应武功套路里面的ResourceAbstractFactory。
2)        具体工厂角色ConcreteFactory对应武功套路里面的PrimaryManagerFactory和AssistantManagerFactory。
3)        抽象产品角色AbstractProduct对应武功套路里面的UIResourceAbstract和AudioResourceAbstract。
4)        具体产品角色ConcreteProduct对应武功套路里面的PrimaryUIManager和PrimaryAudioManager、AssistantUIManager和AssistantAudioManager。

上面描述了抽象工厂模式的修炼心法和武功套路。下面就给出具体的套路细节。
建议:看下面代码之前,可以先根据抽象工厂模式的心法及对应的武功套路先行修炼。

抽象工厂角色:


using UnityEngine;
using System.Collections;

namespace AbstractFactory
{
/// <summary>
/// 定义抽象工厂
/// </summary>
public abstract class ResourceAbstractFactory
{
public abstract UIResourceAbstract CreateUIManager();
public abstract AudioResoucesAbstract CreateAudioManager();
}
}

具体工厂角色:
产品族一:PrimaryManagerFactory工厂


namespace AbstractFactory
{
/// <summary>
/// 定义抽象工厂的具体产品工厂PrimaryManagerFactory
/// </summary>
public class PrimaryManagerFactory : ResourceAbstractFactory
{
public override UIResourceAbstract CreateUIManager()
{
return new PrimaryUIManager();
}

public override AudioResoucesAbstract CreateAudioManager()
{
return new PrimaryAudioManager();
}
}

产品族二:AssistantManagerFactory工厂


using UnityEngine;
using System.Collections;

namespace AbstractFactory
{
/// <summary>
///定义抽象工厂的具体工厂AssistantManagerFactory
/// </summary>
public class AssistantManagerFactory : ResourceAbstractFactory
{
public override UIResourceAbstract CreateUIManager()
{
return new AssistantUIManager();
}

public override AudioResoucesAbstract CreateAudioManager()
{
return new AssistantAudioManager();
}
}

}

抽象产品角色:
音频资源抽象产品


using UnityEngine;
using System.Collections;

namespace AbstractFactory
{
/// <summary>
/// 定义音乐资源抽象类
/// </summary>
public abstract class AudioResoucesAbstract
{
public abstract void LoadConfig(string path);
public abstract void LoadAsset(string name);
public abstract void UnLoadResource(bool status);
}
}

UI资源抽象产品


using UnityEngine;
using System.Collections;

namespace AbstractFactory
{
/// <summary>
/// 定义UI资源的抽象类
/// </summary>
public abstract class UIResourceAbstract
{
public abstract void LoadConfig(string path);
public abstract void LoadAsset(string name);
public abstract void UnLoadResource(bool status);
}
}

具体产品角色:
产品族一:
PrimaryUIManager具体产品


using UnityEngine;
using System.Collections;

namespace AbstractFactory
{
/// <summary>
/// 定义UI抽象类的具体产品PrimaryUIManager
/// </summary>
public class PrimaryUIManager : UIResourceAbstract
{
public override void LoadConfig(string path)
{
Debug.Log("PrimaryUIManager: "+path);
}

public override void LoadAsset(string name)
{
Debug.Log("PrimaryUIManager: "+name);
}

public override void UnLoadResource(bool status)
{
Debug.Log("PrimaryUIManager: "+status);
}
}
}

PrimaryAudioManager具体产品


using UnityEngine;
using System.Collections;

namespace AbstractFactory
{
/// <summary>
/// 定义Audio抽象类的具体产品PrimaryAudioManager
/// </summary>
public class PrimaryAudioManager : AudioResoucesAbstract
{
public override void LoadConfig(string path)
{
Debug.Log("PrimaryAudioManager:"+path);
}

public override void LoadAsset(string name)
{
Debug.Log("PrimaryAudioManager: "+name);
}

public override void UnLoadResource(bool status)
{
Debug.Log("PrimaryAudioManager: "+status);
}
}

}

产品族二:
AssistantUIManager具体产品


using UnityEngine;
using System.Collections;

namespace AbstractFactory
{
/// <summary>
/// 抽象产品的具体产品AssignmentUIManager
/// </summary>
public class AssistantUIManager : UIResourceAbstract
{
public override void LoadConfig(string path)
{
Debug.Log("AssistantUIManager:"+path);
}

public override void LoadAsset(string name)
{
Debug.Log("AssistantUIManager:"+name);
}

public override void UnLoadResource(bool status)
{
Debug.Log("AssistantUIManager:"+status);
}
}

}

AssistantAudioManager具体产品


using UnityEngine;
using System.Collections;

namespace AbstractFactory
{
/// <summary>
/// 抽象产品的具体产品AssistantAudioManager
/// </summary>
public class AssistantAudioManager : AudioResoucesAbstract
{
public override void LoadConfig(string path)
{
Debug.Log("AssistantAudioManager: "+path);
}

public override void LoadAsset(string name)
{
Debug.Log("AssistantAudioManager: "+name);
}

public override void UnLoadResource(bool status)
{
Debug.Log("AssistantAudioManager: "+status);
}
}
}

客户端测试类:


using UnityEngine;
using System.Collections;

namespace AbstractFactory
{
public class ResourceAbstractFactoryClient : MonoBehaviour
{
ResourceAbstractFactory rfPrimary;
AudioResoucesAbstract audioPrimry;
UIResourceAbstract uiPrimary;

ResourceAbstractFactory rfAssistant;
AudioResoucesAbstract audioAssistant;
UIResourceAbstract uiAssistant;

void Start()
{
rfPrimary = new PrimaryManagerFactory();
rfAssistant = new AssistantManagerFactory();
}

void OnGUI()
{
if (GUILayout.Button("主城产品族"))
{
audioPrimry = rfPrimary.CreateAudioManager();
audioPrimry.LoadConfig("http:...");
audioPrimry.LoadAsset("蛮牛");
audioPrimry.UnLoadResource(false);

uiPrimary = rfPrimary.CreateUIManager();
uiPrimary.LoadConfig("http:...");
uiPrimary.LoadAsset("蛮牛");
uiPrimary.UnLoadResource(false);
}

if (GUILayout.Button("副城产品族"))
{
audioAssistant = rfAssistant.CreateAudioManager();
audioAssistant.LoadConfig("http:...");
audioAssistant.LoadAsset("蛮牛");
audioAssistant.UnLoadResource(false);

uiAssistant = rfAssistant.CreateUIManager();
uiAssistant.LoadConfig("http:...");
uiAssistant.LoadAsset("蛮牛");
uiAssistant.UnLoadResource(false);
}
}
}
}

抽象工厂模式的优点:
1)        分离了具体的类,一个工厂封装创建产品对象的责任和过程,将客户端与类的实现分离。有利于产品系列的交换。只需改变具体的工程就可以使用不同的产品配置。
2)        有利于产品的一致性,当一个系列中的产品对象被设计成一起工作时一个应用一次只能使用同一个系列中的对象。
3)        良好的封装性,每个产品的实现类不是高层模块要关心的。更好的遵循了依赖倒置(DIP)的原则。
抽象工厂模式的缺点:
抽象工厂最大的缺点就是产品族扩展非常困难,难以支持新的产品等级结构,如果要支持新的产品等级结构就要扩展抽象工厂接口。这样就涉及到抽象工厂类及所有具体工厂子类的改变,违背了“开放-封闭(OCP)”的原则。

GoF23设计模式里面的每种模式都是针对某类特定问题的解决策略。所以没有什么设计模式是完美的!

Tips:抽象工厂还可以配合.Net 里面的反射技术来去除Switch或If来解除分支判断带来的耦合。同时还可以借助依赖注入(DI)或者专门的IOC来帮助我们克服抽象工厂模式的先天不足。例子大家可以自行搜索查看,或者看Unity3d专用的IOC 框架,例如Strange IOC框架(注:在Unity Asset Store有free download),简单提下,此框架支持web,mobile平台,同时他还有MVC部分扩展,所有的都是针对unity3d的可以学习下。