re: Person owns Dog... Dabay 2008-01-07 14:35
Person Owns Dog问题
这个经典的关于Person和Dog的面向对象编程的问题。它引入了一个有numOfDogsOwned属性和getNumDogsOwned方法的Person类。问题在于这样的设计对于好的设计来说不是必要的,因为Person和Dog是两个独立的概念,Dog的所属关系在Person的最基本的设计中不是必需的。
Page-Jones把这个问题叫做混合关系聚合(mixed-role cohesion),他这样描述这个问题:如果我们想在一个没有Dog参与的应用程序中复用这个Person该怎么办呢?你可以这么做,但是在你的Person类中有一些不必要的包袱。为什么不增加一些更多的诸如numOfCarsOwned、numOfBoatsOwned、numOfCatsOwned的属性,让这个Person类看起来更富有、更通用呢?
这是一个有趣的问题,因为在面对对象的领域里面还没有一个完美的解决方案。Adrian在给出了一个在AspectJ中实现的方式:
public class Person {
private String name;
public String getName() { return name; }
}
要建立一个拥有Dog的Person,但是拥有Dog的并非一定是Person,所以可以把拥有Dog这样一个限定语抽象到一个方面中:
public aspect DogOwnership {
public interface IDogOwnerShip {};
private List IDogOwnerShip.dogs = new ArrayList();
public void IDogOwnerShip.addOneDog(Dog d) { dogs.add(d); }
public int IDogOwnerShip.getNumDogsOwned() { return dogs.size(); }
}
这个方面呈现了一个Dog所属关系的单一模块的概念。其中定义了IDogOwner这样一个接口(它并非一定要实现为一个内部接口的形式,但是这样的可以让他们更好的聚合在一起),然后申明了接口内部的dogs 成员数组,以及addOneDog和getNumDogsOwned来为所有Dog的拥有者提供调用。
到目前为止,还没有这样一个拥有Dog的Person,因为上面的方面只是把Dog的所属关系独立了出来。如果应用程序需要一个拥有Dog的Person的时候,可以这样编写:
public aspect PersonOwnsDog {
declare parents : Person implements DogOwnership.IDogOwner;
}
Class Person和Aspect DogOwnership都是独立的、可复用的,而且用具体方面声名PersonOwnsDog把他们两者绑定起来也是很清楚和简单的。之后,应用程序中完全可以像下面这么使用getNumDogsOwned方法(笔者在Eclipse+ AJDT的环境下已测试通过):
Person person = new Person();
person.getNumDogsOwned();