代码改变世界

依赖于自己做计算

2012-01-17 11:01  康杜  阅读(189)  评论(0编辑  收藏  举报

面向对象设计范式(Object Oriented Design Paradigm)让我们更容易地抽象现实世界的对象,更容易地分析业务。但是,计算机对象不仅仅是现实世界中对象的简单映射。比如针对司机开车(Drivers drive cars)这个场景,在现实世界中开车(drive)是司机的行为,但是在计算机对象世界中, 为了高内聚(High Cohesion),如果Car拥有drive这样行为的所有信息,drive这个动作就应该写到Car对象中,而不是Driver对象中。高内聚,按照我的理解是,’一个类首先要依赖自己做计算‘。

 

下面以一个我工作中的例子阐述,一个类要‘首先依赖自己做计算’这个观点。

image

Figure 1

 

在面对‘判断一个User是否有某某角色’的需求时,我遇到很多人的写法都是设计成这样

image

Figure 2

 

这时候UserManager里有一个方法,像这样子UserManager.hasRole(User user, Role role)。这样的编程设计引进了一个新的类UserManager,增加的新的依赖,导致User对象和Role对象的变化可能引起UserManager的变化。

 

从上面的图片Figure 1中,我们看到User拥有‘判断一个User是否有某某角色’的所有信息,按照‘一个类首先要依赖自己做计算’的观点,hasRole这个方法要放到User对象中,以下是代码片段

public boolean hasAnyRole(String... roleNames) {
        if (roleNames == null) {
            throw new IllegalArgumentException("Role names cannot be null");
        }

        if (this.roles == null || roles.size() == 0) {
            return false;
        }

        for (String roleName : roleNames){
            for (Role userRole : roles){
                if (roleName!=null && roleName.equals(userRole.getName())){
                    return true;
                }
            }
        }
        return false;
}

 

另外一个例子,‘把一个订单保存成订单模板’,我重构之前的设计是这样的:在接口OrderManager中有这样的一个签名 OrderTemplate saveAsTemplate(Order order);

但是,我们知道‘把一个订单保存成订单模板’的业务逻辑是,‘在下订单之前,把用户填写的部分订单信息保存成一个订单模板’。因为订单知道订单模板的所有信息,所以OrderTemplate saveAsTemplate(Order order) 应该写到Order对象里, 代码片段是

public OrderTemplate saveAsTemplate(Order oder){

OrderTemplate orderTemplate = new OrderTemplate();

oderTemplate.setProductId(productId);

return orderTemplate;

}