对于客户端应用程序,免不了和远程服务打交道。设计一个良好的『服务层』能帮咱们规范和分离业务代码,提升生产效率。服务层最核心的模块必定是怎样发送请求,虽然Mono提供了不少C#网络请求类,诸如
WebClient
,HttpWebRequest
,但考虑到跨平台,这些类不必定适用。不过不用担忧,Unity 5.x提供了新的与网络相关类UnityWebRequest
用来替代原先的WWW
,这是官方推荐的,也是最佳选择。git
首先咱们必需要考虑的是,怎样和Web服务安全的通讯。没错,确定是身份验证(Authentication)。对于像WebClient
这些类,它们会提供一个属性,好比Credentials
,能够在此属性设置一些身份验证信息,好比用户名,密码,域。这是一个很『重』的解决方案,且不管是否能在Unity中实现,单从密码这个角度,不少游戏根本不须要密码。因此,咱们须要一种『轻』量级的身份验证机制,这就是Token,中文翻译叫『令牌』。程序员
Token有两个重要的特色:github
第一点咱们确定能够理解,惟一性是身份验证的的基础。那第二点怎么理解呢?其实,Token本质上是一串加密事后的字符串,若是没有时效性,万一被窃取以后,他人很容易进行伪造。因此,易变的Token必定比不变的安全,你须要一个算法来动态生成Token,我提供一个简单的算法:算法
md5(((day*10) + (month*100) + (last2DigitsofYear)*1000)+userId+deviceId)复制代码
同理,你须要在Web服务前加上一个过滤器,同样的算法来验证Token是否一致。编程
Pipeline
是管道的意思,管道是相连的,表明了请求的流转。因为UnityWebRequest
必须配合StartCoroutine
,而StartCoroutine
又属于View层的代码,这和分层(详见以前的文章)冲突,MVVM框架须要将业务逻辑从View解耦。一个比较好的解决方案是经过中介的HttpTool
来解决,它是一个单例的MonoBehaviour
,而且不会随着场景的加载被销毁。json
public class HttpTool : Singleton<HttpTool>
{
// 没法在外界使用构造函数,确保Singleton
protected HttpTool() { }
}复制代码
不论是请求仍是响应,本质上是一堆数据的集合,将这些数据封装成对象的形式会更加容易管理,我将请求相关的数据封装成HttpRequest
对象:数组
public class HttpRequest {
public string Url { get; set; }
public HttpMethod Method { get; set; }
public string Parameters { get; set; }
}复制代码
而将从Web服务返回的数据封装成HttpResponse
对象:安全
public class HttpResponse
{
public bool IsSuccess { get; set; }
public string Error { get; set; }
public long StatusCode { get; set; }
public string Data { get; set; }
}复制代码
值得注意的是,对应Http请求,不论Get仍是Post都会将参数组装成“field1=value1&field2=value2”格式,不一样的是Get请求,参数会跟在Url后,而Post请求则在Request Body里。因此须要一个帮助类,反射要传递的对象属性,拼装返回字符串。网络
核心的请求交由UnityWebRequest
实现,经过yield
等待返回的结果:架构
using (var www = UnityWebRequest.Get(url + parameters))
{
yield return www.Send();
var response = new HttpResponse
{
IsSuccess = !www.isError, Error = www.error, StatusCode = www.responseCode, Data = www.downloadHandler.text
};
onComplete(response);
}复制代码
最后再对返回的Json字符串反序列化成对象,值得注意的是,在此我用了内置的JsonUtility
类,它并不能直接反序列化一个Json数组 ,而是须要将它包装成一个对象 ,经过集合类型属性的形式间接被反序列化。
至此,一个完整的Request Pipeline 以下图所示:
因为JsonUtility
的限制因素多,你可能使用其余第三方的库。又或者不反序列化Json,而是Xml。因此在RemoteRepository
中不该该限制死反序列化的代码,更好的想法是经过『策略模式』,交由外部算法来实现。这样的好处是你根本不须要改动RemoteRepository
里的代码,这也符合『开闭原则』。
因此,你须要在RemoteRepository
定义一个序列化接口:
public ISerializer Serializer { get; set; }复制代码
而后,对返回的HttpResponse
中的Json反序列化:
Serializer.Deserialize<R>(httpResponse.Data)复制代码
真正的对Json序列化器实现了ISerializer
接口,以策略的形式存在:
public class SerializerJson:ISerializer
{
public static readonly SerializerJson Instance=new SerializerJson();
private SerializerJson()
{
}
public string Serialize<T>(T obj, bool readableOutput = false) where T : class, new()
{
throw new NotImplementedException();
}
public T Deserialize<T>(string json) where T : class, new()
{
return JsonUtility.FromJson<T>(json);
}
}复制代码
策略模式在编程领域运用很是广,好比Java或者.NET框架里的集合排序,大量用到策略模式。由程序员指定的算法来最终实现排序。
本文的核心思想就是如何在合理分层结果下构建一个好用的服务层。谈到了如何动态生成Token来实现身份验证,以及分层状况下的请求流程。对于2D而且以数据绑定为基础的游戏,我认为这是一个好的实践方案。由于不论是三层架构仍是N层架构,经过分层的好处是更加清晰去实现业务逻辑。
源代码托管在Github上,点击此了解
欢迎关注个人公众号: