分享
 
 
 

Java中的模式

王朝java/jsp·作者佚名  2008-05-19
窄屏简体版  字體: |||超大  

世上一直有一个神话:设计可以并且应该独立于实现的细节,设计通常被看作是一个抽象的概念而实现是一个代码的具体实例。如果我们坚信"设计是一个富有创造性和目的性的活动:为某一个目标而精心制定的结构的概念,",一个结构如果不能够说明它的环境,或者不能与环境协作,那么这个结构就不适合这一目标。环境中包括目标平台--语言、工具、库、中间件(middleware),等。还有它的功能性和非功能性的单元。

我们会认为在不知道地形布局的时候设计房屋,或者在不清楚使用的道材料的时候建造摩天大厦是不合理的事情。我们将线程、分布这类概念看作为小的编码的细节的看法无疑是在设计中导致浪费精力(时间和金钱)的导火索,最终我们发现的是理论与实践的差距在实践中要比在理论中还大。虽然在一些情况下一个高层次设计的某部分可以在许多技术下保持不变,但是更多的情况是我们需要亲自来补足这个圆圈,允许(甚至鼓励)细节和实际的信息来影响并告知系统的结构。

模式(Patterns)的作用就是获取这些结构上的信息。它们可以描述--预见性的或回顾性的--设计和设计的原理,讲述从问题到解决,说明环境,获取工作的动力以及应此产生的结果。这里,我将集中讲述两个模式--Command-Query Separation和Command Method--为一个类接口中的方法分配任务,考察他们如何互相作用并影响并发的、分布的和有序的环境以及本地执行。

接口设计。顾名思义,接口提供了不同系统之间或者系统不同组件之间的界定。在软件中,接口提供了一个屏障,从而从实现中分离了目标,从具体中分离了概念,从作者中分离了用户。在Java中,有许多接口的概念:public部分为潜在的用户提供了类和方法的接口,protected部分为它的子类(subclass)以及周围的包提供了一个接口;一个包有一个公用的部分;反射(Reflection)是另外一种提供、使用对象方法接口的机制。

约束及供给。站在用户对作者的角度,一个接口建立并命名了一个目的模型的使用方法。类接口中的方法提供了一种特殊的使用方法。是这些约束--编译时的类型系统,运行是的异常机制及返回值--使得类作者的目的得以体现和加强。在这方面最简单的例子是对封装的意义的理解:私有化可以保证类用户只可以通过类的公用方法接口来操作信息和行为。

然而,对于封装来说,远不止数据私有那么简单。在设计中,封装往往会涉及到自我包含(self-containment)。一个需要你知道如何调用一个方法(e.g."在一个线程的环境中,在一个方法调用后调用另一个方法,你必须明确地同步对象")的类的封装就不如将所有这些全部包含并隐藏的类(e.g."这个类是thread-safe的")好。前一个设计存在着设计的漏洞,它的许多限定条件是模糊的而不是经过加强的。这就把责任推给了用户而不是让类提供者做这些工作来完成类的设计,并且,这是不可避免的漏洞百出。

在这种情况下,供给(affordances)描述了使用的可行性和不可行性。

术语供给(affordances)指事物的被感知的真实的属性,首先,这些属性可以决定事物的使用的可能方法。一个椅子可以用来支撑其他东西,所以,可以坐人。一个椅子照样可以搬运(carried)。玻璃可以透光,也可以被打碎……

供给提供了对事物操作的线索,板状物可以压、柄状物可以旋转,沟状物可以插入东西。球状物可以扔或者反弹。当使用了供给的优势后,用户可以只通过看便确定该做什么:没有图、没有标签也没有说明。复杂的事物可能会需要一些解释,但是简单的事物不应该这样。当简单的东西也需要用图片、标签来说明的时候,设计就是失败的。

类设计者的一个职责便是在接口中减小约束与供给之间的隔阂(gap),匹配目标以及一定程度上的自由度,尽可能减小错误使用的可能。

对环境敏感的设计。在空间或者时间上分离方法的执行--例如,线程,远程方法调用,消息队列--能够对设计的正确性和效率产生意义深远的影响。这种分离带来的结果是不可忽视的:并发引入了不确定性和环境选择的开销;分布引入了错误的和不断增加的回程的调用开销。这些是设计的问题,而不是修改bug那样简单。

无论是在何种情况下,结果都是将会阻碍所有权风格的程序设计(Property-Style Programming)--当一个接口主要由set和get方法组成的时候,每个方法都相应的直接指向私有区域。这样的类的封装很差(意思是毫无遮掩)。接口中的域访问器(Field accessors)通常是不会提供信息的:他们在对象的使用中不能通讯、简单化和抽象化,这通常会导致冗长并易出现错误的代码。所有权风格的程序设计在短时间内不是一个大的活动。分布和并行通过引入了正确性和严重的性能开销放大了这些格式上实践的问题。

透明度和bug灾难。抽象允许我们在必要的时候可以忽略细节,所以我们的设计思想可以平衡环境的因素而不是受制于它们。决定什么样的细节可以忽略便成为一个挑战。问题的严重性在重要的细节别忽略的情况下上升了。

设计往往会尽量使环境因素尽可能的透明。透明能够成为一个诱人的主意:也许它可以让线程和远程对象通讯完全透明,这样用户在进行对象通讯的时候什么也不会觉察到。Proxy模式支持一定程度上的透明度。这加强了RMI和COBRA的基础。本地的代理的对象和使用远程的对象在使用中具有相同的接口,并且编组上的细节允许调用着使用熟悉的方法来调用模型。然而,这种分布透明并不完全:失误和潜在的影响,不能被完全隐藏并且需要考虑。毕竟透明不是毛巾。

Command-Query Separation

保证一个方法是不命令(Command)就是查询(Query)

问题。方法,当它们返回一个值来回应一个问题的时候,具有查询的性质,当它们采取强制行动来的改变对象的状态的时候,具有命令的属性。所以一个方法可以是纯的Command模式或者是纯的Query模式,或者是这两者的混合体。

例如,在java.util.Iterator中,hasNext可以被看作一种查询,remove是一种命令,next和awkward合并了命令和查询:

public interface Iterator

{

boolean hasNext();

Object next();

void remove();

}

如果不将一个Iterator对象的当前值向前到下一个的话,就不能够查询一个Iterator对象。这导致了一个初始化(initialization)、增加(continuation)、访问(access)和前进(advance)分离而清晰定义的循环结构的错位:

for(initialization; continuation condition; advance)

{

... access for use ...

}

将Command和Query功能合并入一个方法的的结果是降低了清晰性。这可能阻碍基于断言的程序设计并且需要一个变量来保存查询结果:

for(Iterator iterator = collection.iterator();

iterator.hasNext();)

{

Object current = iterator.next();

... use current...

... again use current...

}

解决方案。保证方法的行为严格的是命令或者是查询,这样可以返回值的方法是纯的函数而没有复效应(side effects),有负效应的方法不可能有返回值。"另一个表述这点的方法是问一个问题而不影响到答案。"

Combined Method

组合方法经常一起被使用在线程和分布环境中来保证正确性并改善效率。

问题。一些主要提供密集的方法的接口,起初,看来是最小化和附着性强的--都是吸引人的特点。然而,在使用的过程中,一些接口显现得过于原始。它们过于简单化,从而迫使类用户用更多的工作来实现普通的的任并操纵方法之间的依赖性(暂时耦合)。这是非常麻烦并且容易出错的,导致了代码重复--代码中应当避免的--并且为bug提供了很好的滋生条件。

一些需要同时执行成功的方法,在执行的时候在多线程、异常、和分布的地方遇到了麻烦。如果两个动作需要同时执行,它们必须遵守协作或反转(commit-or-rollback)语义学--它们必须都完全成功的执行或者一个动作的失败会反转另一个动作的执行--它们由两个独立的方法进行描述。

线程的引入使不确定程度大大增加。一系列方法调用一个易变的(mutable)对象并不会确保结果是料想中的,如果这个对象在线程之间共享,即使我们假设单独的方法是线程安全的。看下面的对Event Source的接口,它允许安置句柄和对事件的查询:

interface EventSource

{

Handler getHandler(Event event);

void installHandler(Event event, Handler newHandler);

...

}

线程之间的交叉调用可能会引起意想不到的结果。假设source域引用一个线程共享的对象,很可能在1、2之间对象被另一个线程安装了一个句柄:

class EventSourceExample

{

...

public void example(Event event, Handler newHandler)

{

oldHandler = eventSource.getHandler(event); // 1

eventSource.installHandler(event, newHandler); // 2

}

private EventSource eventSource;

private Handler oldHandler;

}

同样的,这次也是类使用者而不是类设计者来关注这些,制定约束:

class EventSourceExample

{

...

public void example(Event event, Handler newHandler)

{

synchronized(eventSource)

{

oldHandler = eventSource.getHandler(event);

eventSource.installHandler(event, newHandler);

}

}

private EventSource eventSource;

private Handler oldHandler;

}

如果目标对象是远程的,回程增加的开销和对方法调用失败并发的交织在一起成为环境的一部分。在上一个例子中,我们可以假设执行每一个方法体的时间和通讯的延迟相比是很短的。在这个例子中,开销被重复了两次,并可能在其他的实例

 
 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
2023年上半年GDP全球前十五强
 百态   2023-10-24
美众议院议长启动对拜登的弹劾调查
 百态   2023-09-13
上海、济南、武汉等多地出现不明坠落物
 探索   2023-09-06
印度或要将国名改为“巴拉特”
 百态   2023-09-06
男子为女友送行,买票不登机被捕
 百态   2023-08-20
手机地震预警功能怎么开?
 干货   2023-08-06
女子4年卖2套房花700多万做美容:不但没变美脸,面部还出现变形
 百态   2023-08-04
住户一楼被水淹 还冲来8头猪
 百态   2023-07-31
女子体内爬出大量瓜子状活虫
 百态   2023-07-25
地球连续35年收到神秘规律性信号,网友:不要回答!
 探索   2023-07-21
全球镓价格本周大涨27%
 探索   2023-07-09
钱都流向了那些不缺钱的人,苦都留给了能吃苦的人
 探索   2023-07-02
倩女手游刀客魅者强控制(强混乱强眩晕强睡眠)和对应控制抗性的关系
 百态   2020-08-20
美国5月9日最新疫情:美国确诊人数突破131万
 百态   2020-05-09
荷兰政府宣布将集体辞职
 干货   2020-04-30
倩女幽魂手游师徒任务情义春秋猜成语答案逍遥观:鹏程万里
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案神机营:射石饮羽
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案昆仑山:拔刀相助
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案天工阁:鬼斧神工
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案丝路古道:单枪匹马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:与虎谋皮
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:李代桃僵
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:指鹿为马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:小鸟依人
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:千金买邻
 干货   2019-11-12
 
推荐阅读
 
 
 
>>返回首頁<<
 
靜靜地坐在廢墟上,四周的荒凉一望無際,忽然覺得,淒涼也很美
© 2005- 王朝網路 版權所有