前言
模板方法模式和空对象模式刚刚相反,是经常使用的模式,可能经常用到也不知道它原来叫模板方法模式。
1. 什么是模板方法模式?
这篇就当水文章了,实在想不到这个经常使用到的设计模式,我可以写出什么花里胡哨的东西,而且使用的地方也太多了,写这篇主要是为了完成九九八十一难的其中一难,毕竟其他设计模式都写好了。模板方法是什么?随便找个我之前写过的设计模式文章里基本都隐藏的模板方法模式,主要是封装不变部分的功能,扩展可变部分的功能,各位也可能已经用了很多次了。这里我们介绍一下Gameframework里用到的模板方法模式,具体代码如下:
/// 游戏框架入口。
/// </summary>
public static class GameFrameworkEntry
{
private static readonly GameFrameworkLinkedList<GameFrameworkModule> s_GameFrameworkModules = new GameFrameworkLinkedList<GameFrameworkModule>();
/// <summary>
/// 所有游戏框架模块轮询。
/// </summary>
/// <param name="elapseSeconds">逻辑流逝时间,以秒为单位。</param>
/// <param name="realElapseSeconds">真实流逝时间,以秒为单位。</param>
public static void Update(float elapseSeconds, float realElapseSeconds)
{
foreach (GameFrameworkModule module in s_GameFrameworkModules)
{
module.Update(elapseSeconds, realElapseSeconds);
}
}
/// <summary>
/// 关闭并清理所有游戏框架模块。
/// </summary>
public static void Shutdown()
{
for (LinkedListNode<GameFrameworkModule> current = s_GameFrameworkModules.Last; current != null; current = current.Previous)
{
current.Value.Shutdown();
}
s_GameFrameworkModules.Clear();
ReferencePool.ClearAll();
GameFrameworkLog.SetLogHelper(null);
}
/// <summary>
/// 获取游戏框架模块。
/// </summary>
/// <typeparam name="T">要获取的游戏框架模块类型。</typeparam>
/// <returns>要获取的游戏框架模块。</returns>
/// <remarks>如果要获取的游戏框架模块不存在,则自动创建该游戏框架模块。</remarks>
public static T GetModule<T>() where T : class
{
Type interfaceType = typeof(T);
if (!interfaceType.IsInterface)
{
throw new GameFrameworkException(Utility.Text.Format("You must get module by interface, but '{0}' is not.", interfaceType.FullName));
}
if (!interfaceType.FullName.StartsWith("GameFramework."))
{
throw new GameFrameworkException(Utility.Text.Format("You must get a Game Framework module, but '{0}' is not.", interfaceType.FullName));
}
string moduleName = Utility.Text.Format("{0}.{1}", interfaceType.Namespace, interfaceType.Name.Substring(1));
Type moduleType = Type.GetType(moduleName);
if (moduleType == null)
{
throw new GameFrameworkException(Utility.Text.Format("Can not find Game Framework module type '{0}'.", moduleName));
}
return GetModule(moduleType) as T;
}
/// <summary>
/// 获取游戏框架模块。
/// </summary>
/// <param name="moduleType">要获取的游戏框架模块类型。</param>
/// <returns>要获取的游戏框架模块。</returns>
/// <remarks>如果要获取的游戏框架模块不存在,则自动创建该游戏框架模块。</remarks>
private static GameFrameworkModule GetModule(Type moduleType)
{
foreach (GameFrameworkModule module in s_GameFrameworkModules)
{
if (module.GetType() == moduleType)
{
return module;
}
}
return CreateModule(moduleType);
}
/// <summary>
/// 创建游戏框架模块。
/// </summary>
/// <param name="moduleType">要创建的游戏框架模块类型。</param>
/// <returns>要创建的游戏框架模块。</returns>
private static GameFrameworkModule CreateModule(Type moduleType)
{
GameFrameworkModule module = (GameFrameworkModule)Activator.CreateInstance(moduleType);
if (module == null)
{
throw new GameFrameworkException(Utility.Text.Format("Can not create module '{0}'.", moduleType.FullName));
}
LinkedListNode<GameFrameworkModule> current = s_GameFrameworkModules.First;
while (current != null)
{
if (module.Priority > current.Value.Priority)
{
break;
}
current = current.Next;
}
if (current != null)
{
s_GameFrameworkModules.AddBefore(current, module);
}
else
{
s_GameFrameworkModules.AddLast(module);
}
return module;
}
}
这里的代码是GameFramework动态连接库的入口代码,可以看到框架每个模块的代码都继承于GameFrameworkModule的抽象类,GameFramework一共有UI,Sound,Resource,Download等等模块,具体如图所示:
GameFrameworkModule里有游戏框架的优先级,游戏框架模块轮询,关闭并清理游戏框架模块。这些函数都是游戏模块的共性函数,都可以定义到GameFrameworkModule,具体代码如下:
internal abstract class GameFrameworkModule
{
/// <summary>
/// 获取游戏框架模块优先级。
/// </summary>
/// <remarks>优先级较高的模块会优先轮询,并且关闭操作会后进行。</remarks>
internal virtual int Priority
{
get
{
return 0;
}
}
/// <summary>
/// 游戏框架模块轮询。
/// </summary>
/// <param name="elapseSeconds">逻辑流逝时间,以秒为单位。</param>
/// <param name="realElapseSeconds">真实流逝时间,以秒为单位。</param>
internal abstract void Update(float elapseSeconds, float realElapseSeconds);
/// <summary>
/// 关闭并清理游戏框架模块。
/// </summary>
internal abstract void Shutdown();
}
然后就是Unity里挂载了MonoBehaviour去调用GameFramework.DLL里的GameFrameworkEntry类的函数,虽然这里是继承了GameFrameworkComponent ,但是它继承关系是class GameFrameworkComponent : MonoBehaviour,具体代码如下:
using GameFramework;
using GameFramework.Localization;
using GameFramework.Resource;
using System;
using UnityEngine;
namespace UnityGameFramework.Runtime
{
/// <summary>
/// 基础组件。
/// </summary>
[DisallowMultipleComponent]
[AddComponentMenu("Game Framework/Base")]
public sealed class BaseComponent : GameFrameworkComponent
private void Update()
{
GameFrameworkEntry.Update(Time.deltaTime, Time.unscaledDeltaTime);
}
private void OnDestroy()
{
#if UNITY_5_6_OR_NEWER
Application.lowMemory -= OnLowMemory;
#endif
GameFrameworkEntry.Shutdown();
}
}
Gameframework浅显的原理就是这样,用到了模板方法模式,而且启动了至关重要的模。虽然经常使用这个设计模式,但是它总是会给你意想不到的效果,其实我个人想法其他设计模式不太掌握没太大关系。但单例、工厂、模板方法模式必须要掌握,这些都是属于常用和经典的设计模式。
总结
1.模板方法模式优缺点
优点:1、封装不变部分,扩展可变部分。 2、提取公共代码,便于维护。 3、行为由父类控制,子类实现。
缺点:每一个不同的实现都需要一个子类来实现,导致类的个数增加,使得系统更加庞大。