`
zhc0822
  • 浏览: 228794 次
  • 性别: Icon_minigender_1
  • 来自: 宝仔的奇幻城堡
社区版块
存档分类
最新评论

内存受限下的设计模式(2)——小型接口

阅读更多
背景
模块化带来的好处不言而喻。模块间通过接口互相调用服务,从而实现系统的高内聚与低耦合。
然而接口本身也需要临时内存。在接口间传递数据需要大量的内存。
让我们回忆一下面向对象编程中对于耦合的七种定义。其中推荐的做法之一就是使用所谓“数据耦合”的机制,即在接口间仅传递简单的数据结构、仅传递需要使用的数据。
Android官方编程指南则说的更直白:推荐使用内部类。在极端情况下,没有接口间的互相调用,由此节省下来的内存数量则相当可观了。

模式
因此,我们需要设计出一种让客户可以自由控制数据传输的接口。
那么这里的客户该如何定义呢?根据卡耐基梅隆大学的面向对象教材,调用的一方称为客户(client),而被调用的一方称为对象(object)。为了避免歧义,我们将后者称为服务方。

更深入的探讨
正如前文提到的那样,尽量减少接口间数据传递量是一种很好的方法。现成的例子有很多,比如我们在对mysql进行查询时,通常返回的是一个游标。
然而最小化数据传递的好处,不仅“省内存”,还“省钱”。在一些按照流量计费的场景中,当我们使用移动设备访问web service等,如果对返回的数据进行优化,所需流量就少了,客户需要付出的钞票自然也少了。设想一则天气查询的例子,实在没有必要将某地的经纬度、简介等信息也一并给传给用户。

实现
1、最简单的实现方法如前文所述,传递指针(游标可以看做是一个指针),而不是传递值。

2、当然,步进式接口也是经常采用的策略。如同上文提到的对数据库的访问操作,以及相仿的只要是经由接口传递数据序列或数据群集,都应当将接口设计为步进式,即经过多次调用,获得全部信息,每次调用仅传递一小部分信息而已。当然,也可以通过iterator这样的媒介物而省去多次调用的麻烦。

3、让我们来看一看组件间交换内存的策略。
常用的策略有三种,分别是:借出、借入、转移。

  • 先来看借出(photoshop这玩意还真不适合画流程图...本文的图示都是使用dia画的)。



在借出策略中,客户负责借出一块内存空间给服务方。比如:
// new一个Var对象
Var var = new Var();
Entity.getVar(var);

当var不再需要时,客户必须负责释放它。
var = null;

这种策略特别适合以下场景:1、客户需要拥有对数据完全的控制;2、数据多为简单类型;3、服务方和客户分处不同的内存空间(如Symbian的client-server interface)。
在我之前的文章使用C#和DirectX实时监控麦克风输入音量中,就是在音量计算类中预先分配一个数组,然后再通过DirectX将音频捕捉缓存读入该数组,接着对该数组进行各种运算。

  • 接着来看一下借入策略。



在借入策略中,客户并不分配一块内存空间来缓存数据,它直接借入服务方拥有的对象。然而这种使用是有条件的,即对数据的操作受到限制:
1、试想如果Entity类没有提供setVar方法,那么Action类将无法修改var。
2、并且,当有多个对象同时需要借入服务方拥有的对象时,共享数据问题就出现了。这时需要为共享数据设置同步(如PV操作)。
这种策略特别适合以下场景:1、客户不需要保留数据;2、数据是复杂类型,且客户往往只会用到复杂类型中的一小部分。
在开发中,我们为每一个实体类的类变量创建get和set方法以供调用,这就是一种典型的借入策略的应用。

  • 最后来看一下转移。



在转移策略中,每次Action调用getVar时,Entity都为其初始化一个对象,然后返回此新对象的引用给客户。到目前为止,转移策略的描述更接近借入策略。然而,在转移策略中,客户还要负责对象的销毁。
细心的你看出什么问题没有?转移策略显然增大了不同模块间的耦合,并且对于粗心的程序员来说,他们很可能忘记释放这个不属于他们自己编写的模块的对象,这很容易导致在使用了内存限额设计模式的服务方因为达到内存上限而被终止。
这种策略适用于以下场景:1、客户需要保留数据;3、数据多是复杂类型,且客户往往只会用到其中一部分。
举一个现实生活中的例子。现在某图书馆内有5本《算法导论》(内存限额,5本都借出则不能再借了),每一个读者前去借书时,管理员都会拿出一本《算法导论》给你。管理员并不负责这本书的归还,虽然这本书的确是图书馆的(当然,国外的管理员很有可能会不停地打电话来催你,不过国内的懒惰又傲慢的图书管理员通常不会干这些事情)。当你看完这本书之后(能耐着性子看完《算法导论》的人也算挺厉害的了,反正我没这个耐心),你自己回到图书馆,归还此书。

示例
比较简单,加上我比较懒,就不写了。

预告
下一篇,介绍局部毁弃。
  • 大小: 9 KB
  • 大小: 6.2 KB
  • 大小: 6.5 KB
2
1
分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics