</p> 可以将它改写成下面的形式:6 q/ `# J9 T- {1 o' @! U" B
class Polygon {
' |" R% s. e ]: a% ` …$ V/ f) V+ |; H9 o% O
public int getPerimeter() { return pPolygon.computePerimeter(this);}$ \: u/ M8 N0 e1 ?
public boolean isConvex() { return pPolygon.isConvex(this);}
% q0 @! n. w7 t3 ?6 Z6 `" E" h. G public boolean containsPoint() { return pPolygon.containsPoint(this, p);}5 o! g, M- L5 ~
…6 g: @! O1 \$ z" m+ H. f3 j0 x
}# d! o8 X4 o( ?6 O2 h
在此处,nPolygon应该是这个样子:& }2 k! R2 ~. W) r+ _# @ Q
class pPolygon {3 m1 U5 M1 z! @
static public int computePerimeter(Polygon polygon) {...}( Q. r% c8 W! c; r/ H
static public boolean isConvex(Polygon polygon) {...}
, a5 j$ ?+ G5 u' c: s w6 C static public boolean containsPoint(Polygon polygon, Point p) {...}; W5 q4 c \9 t4 v
}1 f% f6 z2 a$ p# ` T4 b
从类的名字pPolygon可以看出,该类所封装的过程主要与Polygon类型的对象有关。名字前面的p表示该类的唯一目的是组织公共静态过程。在Java中,类的名字以小写字母开头不是一种标准的做法,但象pPloygon这样的类事实上并不执行普通类的功能。也就是说,它并不代表着一类对象,它只是语言本身所需要的用于代码组织的实体。3 X9 y2 {( O' ^" P/ H) N
在上面这个例子中,改动代码的总体影响是使得客户代码不必为了重用其功能而从Polygon继承。Polygon类的功能现在已经由pPolygon类以过程为单位提供。客户代码只使用自己需要的代码,无需关心自身并不需要的功能。3 Q9 z. U. A& E: l
这并不意味着在这种新型的过程化编程模式中,类不服务于更有用的目的。恰恰相反,类执行组织和封装对象数据成员的必要工作。而且它们通过多重接口实现多态性的能力也为代码重用提供了显著的支持,这将在下一个步骤中讨论。然而,由于将功能实现包含在实例方法中无法实现理想的代码重用,所以通过类继承实现代码重用和多态性支持也不应成为最佳的技术选择。* K& f1 X3 A$ e; |% ?7 O7 k5 E& _
在一本被广为阅读的书《Design Patterns》中曾简要地提及一种略有不同的技术。策略模式(Strategy Pattern)提倡将相关算法的每个成员封装在一个通用的接口下,以便于客户端代码可交换地使用其算法。由于一个算法通常被作为一个或几个独立的过程进行编码,这种封装更注重执行单独任务的过程的重用,而不是执行多种任务的、包含代码和数据的对象的重用。这一步骤体现了相同的基本思想。5 A3 ~$ U' o: ]+ h
然而,将一个算法封装在一个接口下意味着将算法作为实现接口的对象进行编码。这意味着我们仍然依赖于一个与所包装的对象的数据和其他方法相耦合的过程,这样便会使其复用变得复杂。此外还存在这样一个问题,每次需要使用这个算法的时候都必须实例化这些对象,这便会降低程序的性能。值得庆幸的是,设计模式提供了针对这两个问题的解决方法。可以在对策略对象进行编码时应用享元模式(Flyweight Pattern,译者注:还存在一种译法为轻量模式),这样每个对象只会存在一个被共知共享的实例(这针对程序性能的问题),而且每个共享对象在访问间隔中并不维持状态(于是对象将没有数据成员,这针对大多数的耦合问题)。由此产生的享元--策略模式非常类似于在这一步骤中所提到的将功能实现封装在全局可见的、无状态的过程中的技术。(译者注:以上这两段文字读起来可能有些晦涩难解,建议有兴趣的读者参阅文中所提到《设计模式》一书,Erich Gamma等著、李英军等译、机械工业出版社出版。) |