求知 文章 文库 Lib 视频 iPerson 课程 认证 咨询 工具 讲座 Modeler   Code  
会员   
 
  
 
 
     
   
分享到
云平台里的小框架设计范例
 
作者 高焕堂,火龙果软件    发布于 2014-03-12
 

前言:在大数据时代里,云平台的角色愈来愈吃重了。其中多层框架云平台成为主流(例如,上层Java+下层C/C++)。然而,云平台的主人只有一个,我们可能只是客人角色,有没有可能反客为主,挟天子以令诸侯呢?这就看架构师的思考技术了。

1. 认识云(端)平台

1.1 以百货公司比喻云平台

传统的网络服务是封闭型的Client/Server架构的延伸。其中的Client与Server两端的软件程序是各自开发的,Server端开发人员撰写完整的Server端程序,而Client端开发人员则撰写完整的Client端程序并且呼叫Server端的程序。这种传统的网络服务系统,其Server端如同一座四合院,庭院深锁,外人(即Client程序)只能在大门口与四合院内的主人沟通。如今的云(Cloud)概念里,其系统架构和软件开发,大多来自传统技术的延伸,并非特别的创新。然而它有了开放心怀,不再紧闭大门、深锁庭院了,而是打开大门,提供庭院让外人进来搭帐篷露营。此外,四合院主人还愿意提供各项资源(软硬件)和服务,甚至免付费呢!

上述的四合院比喻,还不能完整看出云所带来的商业模式和价值。开放型的四合院,也相当于目前大家常常去逛的百货公司,如下图:

图1 云平台就像百货公司

在四合院里搭帐篷,也相当于在百货公司里开设专柜做生意。例如,你到许多百货公司处处可见到香奈儿、SK-II等化妆品专柜,如下图:

图2 百货公司里的连锁专柜(企业)

基于云的开放架构,Android开发者能到各式各样的云(如Google、Facebook等)平台上,开发云层上的应用程序(就如同进入别人的四合院里搭帐篷露营、也如同到各个百货公司开设连锁专柜)。于是,Android应用服务就如同SK-II的国际连锁服务。Android手机端成为连锁店的营运总部,Android手机也成为连锁店总经理的随身指挥利器,和运筹帷幄中心了。

1.2 以连锁专柜比喻特定领域的(跨)云平台

一般而言,有两种常见的云分类:

公有云(Public Cloud)-- 开放给各行业或各领域的人们进来写软件或使用服务。

私有云(Private Cloud)-- 并不开放给别人进来写软件或使用服务。

如果你学过Java或C++的话,就知道类别里的函数可分为:public、private和protected共三种。如果对应到云的分类别上,将可以得到第三种云,就是:

限定云(Protected Cloud),即<特定领域的云(Domain-Specific Cloud)>-- 特定领域就是特定行业,例如医疗行业、物联网行业、保险行业、网络游戏行业、KTV行业等,各有其专属(Protected)范围。只开放熟悉该行业的人进来写软件或使用服务。例如,医疗领域云平台的系统架构图如下:

图3 医疗领域的(跨)云平台

从图可以看出来,这个医疗领域云平台,是建立于多的公有(Public)云平台上,甚至,可能也有自己的私有(Private)云。所以它是一种跨云(公有及私有)的云。由于它是建立于公有云的虚拟平台上,不需要巨大投资于硬设备上,所以建置成本远低于公有云。欲理解这种新潮跨云平台的最好比喻就是:

公有云,如同「百货公司」。

特定领域云,如同百货公司里的 Chanel连锁专柜。

大家都知道:跨百货公司的连锁专柜也是公司,所以跨公有云的特定领域跨云平台,也是云。

2. 认识GAE(Google AppEngine)云平台

GAE(Google AppEngine)是Google的云服务引擎,第三方应用程序开发者能开发应用程序(AP),然后放在Google服务器上执行,不需担心频宽、系统负载、安全维护等问题,一切由Google代管。只要AP每月不超过500万网页面的流量就可享受免费的待遇。GAE平台的系统架构如下图:

图4 GAE云平台架构(摘自Google公司文件)

从上图可看到,从手机、PC、MID等众多端设备上,都能随时上网发出要求(Incoming Requests)来存取GAE上的服务。在GAE后台的AppServer里,GAE提供了API(即API Layer)来衔接你的云端应用程序(即AP)。

3. 小强龙的云框架API-- 以GAE的SM游戏为例

水果盘拉霸机(Slot Machine,简称SM)游戏。如下图:

图5 Android拉霸机游戏画面

其玩法是先输入投注金额(Bet),然后拉动点击把手或点击<SPIN>钮来转动滚动条,滚动条会各自转动,然后随机出现不同图案,如果停定时,有出现符合相同或特定相同图案连成线者,即依其赔率而胜出。同一家游戏场里的拉霸机通常会联网,以投注额厘定累积大奖(Jackpot)金额,并随时更新累绩大奖金额,以便增加吸引性。

3.1 SM游戏的框架设计图

这游戏软件可分为两部分:

游戏(Game)端部分,也就是Android手机端的应用程序。

柜台(Console)端部分,也就是GAE云层Servlet程序。

当玩家押注后,按下<SPIN> 按钮(开始加速滚动),游戏端就将「目前余额」和「押注金额」传送给GAE的柜台端程序。等待柜台端程序计算出中奖金额后,将「新余额」和「奖项级别」回传给Android游戏端(滚动开始减速),并更新游戏端的画面。其中,Android游戏端程序(ac01.java)发送HTTP来呼叫GAE云层的Servlet接口,如下图所示:

图6 拉霸机游戏的系统架构图

Android游戏端透过HTTP和Servlet接口来传送三种讯息给GAE 云层。这三种讯息为:

当玩家启动Android游戏端时,发送"Init:"讯息给GAE云层程序-- GAE就从DB里读取玩家的余额(即上回的余额),并回传给游戏端。

当玩家按下<SPIN>按钮时,发送"Bett:amount,bet" 讯息给GAE云程序-- 此讯息附有余额(amount)和押注金额(bet),要求GAE程序决定「奖项级别(Rank)」,计算奖金和新余额,然后回传给游戏端。

当玩家欲结束时,按下<Exit>按钮发送"Fini:amount"讯息给GAE云层-- 此讯息附有目前余额(amount),GAE接到讯息,就依据将余额存入DB,完成时立即回复给游戏端,关闭游戏端画面。

GAE Console端应用程序包含两个部份:Servlet模块和GM模块。GM(全名是Game Machine)类别是Console端应用程序的决策核心,例如决定游戏获奖的奖项,计算奖金等都是GM负责的任务。至于Servlet类别体系则是负责与Android游戏端的沟通任务。

◆ Slot Machine的框架设计图(方案一)

兹先设计(和开发)Slot Machine应用框架,如下图所示:

图7 Console端游戏框架设计图(依据方案一)

当Android游戏端(简称SM)呼叫HttpServlet类别的Servlet接口时,会转而呼叫smConsoleStub类别的doGet()函数,此doGet()转而呼叫process()函数去解析来自Android游戏端的讯息,然后呼叫GM类别的函数,或呼叫应用程序的onInitialAmount()和onFinished()函数。

值得留意的是,此框架设计者(即smConsoleStub类别设计者)决定了它与游戏端沟通的讯息格式(Format),例如游戏端必须使用"Init:"讯息格式、"Bett:"讯息格式和"Fini:"讯息格式。一旦框架设计者决定了沟通接口,则应用程序开发者就必须遵循这些接口,而不能更改之。此时,框架就藉由这些接口来「框住」应用程序(及开发者)了。此外,框架也决定了它与子类别间的接口,也就是决定了onInitialAmount()和onFinished()函数的名称及参数格式。例如下图:

图8 Console端的应用子类别(smConsoleServlet)

其中,smConsoleServlet子类别就必须遵循smConsoleStub类别的接口规定而实作(Implement) onInitialAmount()和onFinished()两个抽象函数。

◆Slot Machine的框架设计图(方案二)

在上述方案一里,框架设计师决定了Android游戏端与云层之间沟通讯息的格式,而应用程序开发者只能遵循之而不能制定自己喜欢的讯息格式。如果想让应用程序开发者能自行决定上述的讯息格式,就可更改框架设计如下图:

图9 Console端游戏框架设计图(依据方案二)

在此新方案里,smConsoleStub22类别的process()是抽象函数,让应用程序的smConsoleServlet22子类别来实作之。框架里的smConsoleStub22类别只是将讯息转达给应用子类别smConsoleServlet22而已,并不决定讯息格式,也不解析讯息。而是由smConsoleServlet22子类别的process()函数来解析讯息。由于Android游戏端的ac01类别和云层的smConsoleServlet22子类别都属于应用程序,由ac01类别与smConsoleServlet22子类别之间的沟通讯息格式,是应用开发者可以自订了。

3.2 SM游戏的云端框架范例代码

这云层框架是依据上述的方案一而设计的,其包含两个类别:GM类别和smConsoleStub类别。兹在GAE开发项目里定义上述类别,如下图:

兹撰写GM.java类别和smConsoleStub.java类别,其代码如下:

其中,RC类别是依据随机值而换算出获奖的奖项(Rank),其实各家游戏场都有不一样的奖项决定规则,而且随时都可能更换新的奖项规则。上述RC类别只是一个简单范例而已。Android游戏机端传送HTTP讯息给GAE云层,就转而呼叫上述的doGet()函数。此时诞生一个GM对象,并从session取得"gmState"的值,并将此值存入GM对象里,设定了GM对象的状态值。接着,转而呼叫process()函数来解析讯息内容,在依据内容而呼叫GM对象的函数或应用子类别的函数,最后回传讯息给游戏机端。

3.3 SM游戏的应用程序(App)范例代码

这拉霸机应用程序包括:GAE云层的smConsoleServlet子类别和Android游戏端的ac01子类别。

GAE云层的应用程序代码

其包括smConsoleServlet子类别。兹在GAE开发项目里定义之,如下:

兹撰写smConsoleServlet类别,其程序代码如下:

/*---- smConsoleServlet.java ----*/

package misooGAE001;

import com.google.appengine.api.users.User;

import GameFramework.smConsoleStub;

@SuppressWarnings("serial")

public classsmConsoleServletextends smConsoleStub{

@Override protected int onInitialAmount(User user) {

// 读取user's initial(recorded) amount from DB

int init_amt = 1000;

return init_amt;

}

@Override protected boolean onFinished(User user, int final_amount) {

// 将user's final amount 存入 DB

return true;

}}

云层框架smConsoleStub类别并不负责向DB存取游戏玩家的目前余额。所以在游戏启动时,smConsoleStub呼叫应用程序子类别smConsoleServlet的onInitialAmount()函数去DB读取玩家的余额。而且在游戏结束时,框架类别smConsoleStub则呼叫应用程序子类别smConsoleServlet的onFinished()函数去将玩家余额写入DB里,储存起来。

Android游戏端应用程序代码

应用程序开发者除了上述smConsoleServlet子类别之外,还要开发Android游戏端的应用程序。兹在Android开发项目里定义ac01子类别,如下图:

兹撰写ac01.java子类别,其程序代码如下:

此ac01类别的invokeServlet()函数会启动一个子执行绪(Thread)去发送HTTP讯息给GAE云层的Servlet程序。例如,游戏启动时,立即发送"Init:"讯息给云层,此时画面上出现一个「等待」窗口,如下图:

一直等到接获云层Servlet回复时,就出现测试用的简易游戏画面,如下:

其中的Amt:1000表示目前此玩家的余额是1000元。此时,玩家可以连续按下<Add>按钮来投注更多金额。例如,投注100元的画面如下:

此时,玩家可按下<SPIN>按钮,ac01类别的invokeServlet()函数会启动一个子执行绪(Thread)去发送"Bett:"讯息给云层,此时画面上出现一个「等待」窗口。一直等到接获云层Servlet回复时,就出现更新游戏画面上的金额,如下:

其中的Rank:3 表示获得第3级别的奖项,押注100元,赢得300元奖金,目前余额为1300元。当玩家按下<Exit>按钮,ac01类别的invokeServlet()函数会启动一个子执行绪(Thread)去发送"Fini:"讯息给云层,此时画面上出现一个「等待」窗口。一直等到接获云层Servlet回复时,就表示云层已经将余额存入DB,于是ac01就结束了。

3.4 搭配上漂亮的UI画面

上述的拉霸机范例程序,只要将Android游戏端应用程序更换掉,就可以换上漂亮的操作画面了,如下图所示:

图10 美观的Android拉霸机游戏画面

然而,由于篇幅的限制,本范例只采用简易操作画面,以便列出完整的程序代码。

4. Android框架 + GAE框架

Android的跨进程界面IBinder,其角色相当于云层里的Servlet界面:

图11 Android端框架与GAE云框架的完美整合

无论Android还是GAE云层都是以框架来支撑「强龙/地头蛇」商业样式。 兹写个GAE框架范例,并进行架构设计如下:

图12 Android框架+ GAE框架的范例

其中的UploadPost和myUploadPost两个类别的程序代码如下:

//UploadPost.java

package com.patrick.ccpmediastore;

import java.io.IOException;

import java.net.URLEncoder;

import javax.servlet.http.HttpServlet;

import javax.servlet.http.HttpServletRequest;

import javax.servlet.http.HttpServletResponse;

@SuppressWarnings("serial")

public abstract class UploadPost extends HttpServlet {

 public void doPost(HttpServletRequest req, HttpServletResponse resp)

          throws IOException {

   try { PMF.get().getPersistenceManager().makePersistent(getMediaObject(req));

                      resp.sendRedirect("/");

              } catch (Exception e) {

                      resp.sendRedirect("/?error=" +

                      URLEncoder.encode("Object save failed: " + e.getMessage(), "UTF-8"));

           }}

       protected abstract MediaObject getMediaObject(HttpServletRequest req) ;

}

// myUploadPost.java

package com.patrick.ccpmediastore;

import java.io.IOException;

import java.util.Date;

import java.util.Iterator;

import java.util.Map;

import javax.servlet.http.HttpServletRequest;

import javax.servlet.http.HttpServletResponse;

import com.google.appengine.api.blobstore.*;

import com.google.appengine.api.users.User;

import com.google.appengine.api.users.UserService;

import com.google.appengine.api.users.UserServiceFactory;

@SuppressWarnings("serial")

public class myUploadPost extends UploadPost {

private BlobstoreService blobstoreService =

BlobstoreServiceFactory.getBlobstoreService();

protected MediaObject getMediaObject(HttpServletRequest req) {

UserService userService = UserServiceFactory.getUserService();

User user = userService.getCurrentUser();

Map<String, BlobKey> blobs = blobstoreService.getUploadedBlobs(req);

Iterator<String> names = blobs.keySet().iterator();

String blobName = names.next();

BlobKey blobKey = blobs.get(blobName);

BlobInfoFactory blobInfoFactory = new BlobInfoFactory();

BlobInfo blobInfo = blobInfoFactory.loadBlobInfo(blobKey);

String contentType = blobInfo.getContentType();

long size = blobInfo.getSize();

Date creation = blobInfo.getCreation();

String fileName = blobInfo.getFilename();

String title = req.getParameter("title");

String description = req.getParameter("description") + "from myNewUploadPost";

boolean isShared = "public".equalsIgnoreCase(req.getParameter("share"));

      MediaObject mediaObj = new MediaObject(user, blobKey, creation,

contentType, fileName, size, title, description, isShared);

return mediaObj ;

}}

 一样的框架设计思维、方法和技术,应用于Android行动端上,同时应用于GAE云层上。

 
相关文章

云计算的架构
对云计算服务模型
云计算核心技术剖析
了解云计算的漏洞
 
相关文档

云计算简介
云计算简介与云安全
下一代网络计算--云计算
软浅析云计算
 
相关课程

云计算原理与应用
云计算应用与开发
CMMI体系与实践
基于CMMI标准的软件质量保证
 
分享到
 
 


专家视角看IT与架构
软件架构设计
面向服务体系架构和业务组件的思考
人人网移动开发架构
架构腐化之谜
谈平台即服务PaaS
更多...   
相关培训课程

云计算原理与应用
Windows Azure 云计算应用

摩托罗拉 云平台的构建与应用
通用公司GE Docker原理与实践
某研发中心 Openstack实践
知名电子公司 云平台架构与应用
某电力行业 基于云平台构建云服务
云计算与Windows Azure培训
北京 云计算原理与应用