由一个例子想到对事务脚本模式的问题

来源:互联网 发布:指纹打卡机导出数据 编辑:程序博客网 时间:2024/04/27 19:28
比如订单和订单项的管理
一个订单有多个订单项
class Order{
List<Item> items;
}
假如我的订单有添加订单项的方法,那么我们必然有一个Service叫
class OrderService{
public void addItem(Order order,Item item){
order.items.add(item);
this.save(order);
}
public void save(Order order){
this.orderDao.save(order);
}
}


假如一个开发客户端的程序员在做一个添加订单项的功能
一般情况下,他会这么调用
orderSerivce.addItem(order,item);
但是不排除别的情况下,我调用了order.items.add(item)后,又调了save方法
表面看来,这好像没有什么问题


假如有一天,我的功能增强了,我在每添加一个订单后要计算order的总价
public void addItem(Order order,Item item){
order.items.add(item);
this.calculateTotalPrice(order);
this.save(order);
}
问题出现了,第二种写法绕过了,计算总价(这应该算一个bug)
由测试人员反馈给了程序员,程序员会说这很简单啊,于是在save方法中也加了一个这样的代码
public void save(Order order){
this.calculateTotalPrice(order);
this.orderDao.save(order);
}
然后问题似乎解决了,但是第一种方法计算了两次总价,多计算了一次也不会引发什么错误,可是一但我又增加了新的功能
我可以手动调整当前订单价格,也是有可能的,和老板商量了少收一块钱,然后添加了一个订单项,发现少收的一块钱又加回来了
于是程序员又开始改,好像不能重新计算,于是改为了每添加一个订单项,就把当前订单项的price加进去,
public void addItem(Order order,Item item){
order.items.add(item);
order.addToTotalPrice(item.price);
this.save(order);
}
这下呵呵了,第二种调用方法没法改了,只能让客户端开发人员去修改,不让直接通过items添加,增加了很多沟通成本


这个就像借钱一样,A和B借钱,A要通过B,让B拿出钱,这时候,B应该知道自己的钱借出去多少还剩下多少,应该还多少,
如果开放items的访问,就相当于B的钱包是敞开的,任何人都可以直接不通过B去借钱,这样B就不清楚他还剩多少钱,也不知道借给了哪些人


所以我们应该把自己的钱包藏起来


class Order{
private List<Item> items;
public List<Item> getItems{
List items= new ArrayList();
items.addAll(this.items);
return items;
}
public addItem(Item item){
this.items.add(item);
this.addTotalPrice(item.price);
}

}


这样我们不管通过什么方式来计算总金额,只需改addItem方法就可以了,省去了很多事情


总结:事务脚本的编码模式破坏了面向对象的封装特性。。




0 0
原创粉丝点击