Java中的模式(二)

2014-11-24 07:45:45 · 作者: · 浏览: 2
();)
{
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;

}

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

此外还有一个问题是对外部(extern)的synchronized同步块的使用需求。Synchronized块很明显在分布的环境中使用但是也可以在本地的线程环境中应用的很好:在调用者和目标之间的代理对象的使用。简而言之,对synchronized块的使用因为代理对象而不是目标对象的同步而失败。保守的说法是,这对系统的真确性可以有一个基本的影响。因为代理使用是在接口后透明的,调用者不能对行为做太多的保证。

解决方案。Combined Method必须在分布,线程环境中同时执行。联合应当反映出普通的使用方法。这样,一个Combined Method才可能比原有的方法要清晰,因为它反映了直接的应用。恢复策略和一些笨拙的方法被封装到Combined Method中,并简化了类用户角度的接口。这改善的封装降低了接口中不需要的累赘。Combined Method的全部效果是支持一种更像事务处理风格的设计。

在一个联合的Command-Query中提供一个单独的Query方法通常是合理的。然而,这需要按照需要而制定,而不是强制的执行。提供分离的Command方法是不太常见的,因为Combined Method可以完成这一工作:调用者简单的忽略结果。如果返回一个结果招致一个开销的话,才可能会体统一个单独的Command方法。

回到前一个例子中,如果installHandler method返回上一个句柄设计变得更加简单和独立:

class EventSourceExample

{

...

public void example(Event event, Handler newHandler)

{

oldHandler = eventSource.installHandler(event, newHandler);

}

private EventSource eventSource;

private Handler oldHandler;

}

调用者提供了一个更加安全接口,并且不再需要解决线程的问题。这降低了风险和代码的大小,将类设计的职责全部给了类设计者而不是推给用户。代理对象的出现没有影响到正确性。

一个Combined Method可以是许多Query的集合,许多Command的集合,或者两者兼有。这样,它可能补充或者抵触Command-Query分离的方法。当冲突发生的时候,优先选择Combined Method会产生一个不同的正确性和适用性。

在另一个例子中,考虑获得资源的情况。假设,在下面的接口中,获得的方法在资源可用前一直起到阻碍作用:

interface Resource

{

boolean isAcquired();

void acquire();

void release();

...

}

类似于下面的代码会在一个线程系统中推荐使用:

class ResourceExample

{

...

public void example()

{

boolean acquired = true;

synchronized(resource)

{

if(!resource.isAcquired())

resource.acquire();

else

acquired = false;

}

if(!acquired)

...

}

private Resource resource;

}

然而,即使放弃可读性和易用性,这样的设计不是一个Command-Query分离设计的应用。如果引入了代理,它就会失败:

class ActualResource implements Resource {...}

class ResourceProxy implements Resource {...}

一个Combined Method解决了这个