Unity设计模式—服务定位器模式
Posted NickPansh
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Unity设计模式—服务定位器模式相关的知识,希望对你有一定的参考价值。
服务定位器模式
概要
为某服务提供一个全局访问入口来避免使用者与该服务具体实现类耦合
游戏编程中,某些对象或者系统几乎出现在程序的每个角落。如音频,UI管理等。
直接引用对象肯定最差,用单例也不好,更合适的方案是引入服务定位器。
它使用起来像一个更灵活,更可配置的单例模式。
类结构
一个服务类为一系列操作定义了一个抽象的接口。
若干个具体服务提供器实现这个接口。
一个单独的服务定位器通过查找合适的提供器来提供这个服务的访问。
实现
jarjin/LuaFramework_UGUI的Facade就是用了服务定位器模式。
我在它的基础上结合《游戏编程模式》的服务定位模式设计了新的服务定位器,引入了空对象服务,让整个系统更易于使用。
Locator
// 服务定位器
public class Locator
private static Dictionary<string, IManager> _managers = new Dictionary<string, IManager>();
private static Dictionary<string, IManager> _nullManageCache = new Dictionary<string, IManager>()
typeof(AudioManager).Name, new NullAudioManager() ,
typeof(NetworkManager).Name, new NullNetworkManager() ,
;
static Locator()
/// <summary>
/// 获得管理器
/// </summary>
/// <typeparam name="T">IManager</typeparam>
/// <returns></returns>
public static T GetManager<T>() where T : class, IManager
string mgrName = typeof(T).Name;
// 若字典中没有对应的管理器,则返回对应的空管理器
if (!_managers.ContainsKey(mgrName))
if (_nullManageCache.TryGetValue(mgrName, out IManager nullMgr))
return nullMgr as T;
else
return default(T);
return (T)_managers[mgrName];
/// <summary>
/// 添加管理器
/// </summary>
/// <typeparam name="T">IManager</typeparam>
/// <param name="mgr">instance of T</param>
/// <returns></returns>
public static T AddManager<T>(T mgr) where T : class, IManager
string mgrName = typeof(T).Name;
if (_managers.ContainsKey(mgrName))
_managers[mgrName] = mgr;
else
_managers.Add(mgrName, mgr);
return mgr;
public static void RemoveManager<T>() where T : class, IManager
string mgrName = typeof(T).Name;
if (_managers.ContainsKey(mgrName))
_managers.Remove(mgrName);
AudioManager&NullAudioManager
public class AudioManager : IManager
public virtual void PlaySound(string soundName)
Debug.Log("PlaySound:" + soundName);
// 空管理器
// q:为什么它继承自AudioManager而不是声明IAudioManager后NullAudioManager和AudioManager都实现IAudioManager呢?
// a:希望Locator在AddManager<T>()时,传的是AudioManager而不是IAudioManager,所以NullAudioManager必须继承自AudioManager
// 否则 return nullMgr as T;会返回空。比起空Manager持有变量占用内存的缺点而言,更看重Locator调用时方便易懂。
public class NullAudioManager : AudioManager
public override void PlaySound(string soundName)
// Do nothing
Debug.Log("Do nothing:");
调用代码:
// 注册服务
// Register the service
AudioManager audioMgr = new AudioManager();
Locator.AddManager<AudioManager>(audioMgr);
NetworkManager networkMgr = new NetworkManager();
Locator.AddManager<NetworkManager>(networkMgr);
// 调用管理器
Locator.GetManager<AudioManager>().PlaySound("Sound1");
// 移除管理器
Locator.RemoveManager<NetworkManager>();
我见
服务定位器模式比单例模式要好得多,它比起单例模式好拓展的多。
-
我们可以通过装饰器模式来装饰一个原有的服务,来轻易地拓展原有的服务。
-
现在我们也不用担心单例的一些初始化步骤在哪里进行—只要用空对象模式即可。
-
我们可以在运行时更换服务。
源码
完整代码已上传至nickpansh/Unity-Design-Pattern | GitHub
其他设计模式
专题 | Unity3D游戏开发中的设计模式 | 问渠 (wenqu.site)
设计模式-服务定位器模式
上文(设计模式-拦截过滤器模式):
背景
服务定位器模式是什么?
服务定位器模式可以干嘛?
个人理解:
服务定位器模式类图
源码下载:https://gitee.com/hong99/design-model/issues/I1IMES
实现代码
/**
* @Auther: csh
* @Date: 2020/7/5 11:44
* @Description:抽象的服务接口
*/
public interface IUserInfo {
public String getName();
public void printUserInfo();
}
/**
* @Auther: csh
* @Date: 2020/7/5 11:45
* @Description:用户信息(Service)
*/
public class User implements IUserInfo {
private String userName;
public void setUserName(String userName) {
this.userName = userName;
}
private User() {
}
public User(String usreName) {
this.userName = usreName;
}
public String getName() {
return userName;
}
public void printUserInfo() {
System.out.println("用户信息:"+this.getName());
}
public String toString() {
return "User{" +
"userName='" + userName + '\'' +
'}';
}
}
/**
* @Auther: csh
* @Date: 2020/7/5 11:48
* @Description:创建对象(Context )
*/
public class InitialContext {
private static InitialContext initialContext = new InitialContext();
private InitialContext(){
}
public static InitialContext getInstance(){
return initialContext;
}
public Object lookup(String username){
return new User(username);
}
}
/**
* @Auther: csh
* @Date: 2020/7/5 11:51
* @Description:用户缓存
*/
public class UserCache {
private List<IUserInfo> userInfos;
public UserCache() {
userInfos = new ArrayList <IUserInfo>();
}
public IUserInfo getUserInfo(String userName){
for (IUserInfo userInfo : userInfos) {
if(userInfo.getName().equalsIgnoreCase(userName)){
System.out.println("从缓存中获取到用户信息:"+userInfo.toString());
return userInfo;
}
}
return null;
}
public void addUserInfo(IUserInfo userInfo){
boolean exist = false;
for (IUserInfo info : userInfos) {
if(info.getName().equalsIgnoreCase(userInfo.getName())){
exist = true;
}
}
if(!exist){
userInfos.add(userInfo);
}
}
}
/**
* @Auther: csh
* @Date: 2020/7/5 12:06
* @Description:服务定位器(Service Locator)
*/
public class UserInfoLocator {
private static UserCache userCache = new UserCache();
public static IUserInfo getUserInfo(String userName){
IUserInfo userInfo = userCache.getUserInfo(userName);
if(userInfo!=null){
return userInfo;
}
InitialContext instance = InitialContext.getInstance();
IUserInfo user = (IUserInfo)instance.lookup(userName);
userCache.addUserInfo(user);
return user;
}
}
/**
* @Auther: csh
* @Date: 2020/7/5 12:51
* @Description:服务定位器模式
*/
public class Client {
public static void main(String[] args) {
IUserInfo userInfo = UserInfoLocator.getUserInfo("user1");
userInfo.printUserInfo();
userInfo = UserInfoLocator.getUserInfo("user2");
userInfo.printUserInfo();
userInfo = UserInfoLocator.getUserInfo("user1");
userInfo.printUserInfo();
}
}
结果
用户信息:user1
用户信息:user2
从缓存中获取到用户信息:User{userName='user1'}
用户信息:user1
源码下载:https://gitee.com/hong99/design-model/issues/I1IMES
最后
参考文章:
https://www.oracle.com/technetwork/java/servicelocator-137181.html
http://gameprogrammingpatterns.com/service-locator.html
以上是关于Unity设计模式—服务定位器模式的主要内容,如果未能解决你的问题,请参考以下文章