跨越分析与设计的鸿沟

如何把分析转化为设计,又如何把设计模式跟域模型结合? 这里边如何还操作,总有章可循. 各位有何高见.现在举个例比较好说明问题.

现有一个库存检查的逻辑:

对A类别的产品: 不需要库存检查,可下单, 对B类别的产品: 一定要库存检查,有库存可下单,无库存不能下单 对C类别的产品: 购买该类别的客户需要选择送货周期,如果 客户要求的送货周期大于30天,是不需要检查库存(即30天后一定可以送货),如果小于30天需 要检查库存.

以后可能还有其它类别的处理逻辑,这里有两处变化.产品类别 以及 该类别的库存处理逻辑.这个似乎,可以用Bridge 模式来解决扩展问题.现在的问题是:如何把这个设计跟原来的模型整合起来. 这个产品类别不知道如何来抽象化.如果用这个设计,那么用这个接口OrderService需要判断产品类别,然后创建不同的处理逻辑.

现有一个大概的设计图:

[该贴被willem于2008-06-18 13:34修改过]

这些设计类,如果按DDD规则来分层,如何归类呢?

abstract class Category{
    abstract void accept(CheckStock cs);
}
class ACategory extends Category{
    void accept(CheckStock cs){
        cs.check(this);
    }
}
interface CheckStock{
    void check(ACategory a);
    void check(BCategory b);
}
class Checker implements CheckStock{...}
不知这样如何,因为我觉得是否检查是Category相关的。 [该贴被freebox于2008-06-18 16:21修改过]

感觉是Visitor模式. 完全不是 原来 的 Bridge 模式.思考中......

而且Visitor模式有一个不好的地方,如果我的产品类别经常变动,Visitor在这里就要改动. [该贴被willem于2008-06-18 18:20修改过]

我想请教freebox ,为什么你想到的是这种设计方案(Visitor模式), 能否把你的思考过程讲一下,谢谢

虽然这些个模式都很熟悉,但老用错,怎么用设计模式总有个章法.比如从哪个方面分析入手等等. 我再比较了一下这两个模式,一个是行为,一个结构. 而上面的逻辑应该是行为. 似乎从设计模式的分类来入手也是一个方面.

也许和您所说的原来的Category意义不同,原来的多个Category可能使用同一种检查方案。我的Category拥有“检查方案类别”的意义,就是“不检查、总检查这些,以及等等”。 我也不确定这个方案就是适用的,并且我不知道这就是Visitor模式(不是说您说这是Visitor模式说错了,是我在概念上不清楚),仅仅是觉得应该这样设计。 理由就是您说的检查方案(该类别的库存处理逻辑)和检查方案类别(产品类别或产品类别的集合所具有的检查类别)都有可能变化。 改个名字:

class Category{
    CheckKind kind;
}
abstract class CheckKind{
    abstract void accept(CheckStock cs);
}
class NeverCheckKind extends CheckKind{
    void accept(CheckStock cs){
        cs.check(this);
    }
}
interface CheckStock{
    void check(NeverCheckKind a);
    void check(AlwaysCheckKind b);
}
class Checker implements CheckStock{...}
[该贴被freebox于2008-06-18 21:18修改过]

abstract class CheckKind
{    
      abstract void accept(CheckStock cs);
}

这个抽出来了,比较好

楼上讨论很不错,Freebox的设计方案看起来还是合适恰当的。

我想补充的是:checkStock绝对不能放入OrderService中,因为checkStock是重要的下单判断标准,属于业务逻辑,根据Evans DDD和充血理论,业务逻辑应该进入领域模型,而不是服务OrderService

Evans DDD中有一个类似案例展示过滤筛选,大概是发票是否过期的判断,根据Domain Model又建立了一个Proxy对象用来封装判断发票是否过期,反正发票是否过期不能进入服务。

checkStock放入OrderService中,还是按常用的分层架构套路, 用Proxy,我倒要试试,最终的service层,我想应该是很薄的一层.

checkStock不能放入OrderService,要坚持静态决定动态的原则。下面贴一下我的设计,不足之处,请大家指正,共同讨论改进。 //订单 public class Order implements Serializable {

private String No; private List items;

//检查库存是否足够 public boolean checkStorage(){ boolean result = false; for (Iterator itr = items.iterator(); itr.hasNext();){ OrderItem item = (OrderItem)itr.next(); result = item.IsStorageEnough(); if (!result){ break; } } return result; } }

//订单项 public class OrderItem implements Serializable {

private String No; //序号 private Product product; //产品 private Double qty; //数量 private long deliveryPeriod; //送货周期

//检查库存是否足够 public boolean IsStorageEnough(){ ICheckStorage checker = null; if (product.getCategory().getCode().equals("A")){ checker = new ACheckStorage(); } else if (product.getCategory().getCode().equals("B")){ checker = new BCheckStorage(); } else if (product.getCategory().getCode().equals("C")){ if (deliveryPeriod > 30){ checker = new ACheckStorage(); }else checker = new CCheckStorage(); } return checker.checkStorage(product, qty); }; }

//订单仓储 public class OrderRepository { public void save(Order order){ } }

//产品 public class Product implements Serializable {

private String ID; private String code; private ProductCategory category; }

//产品类别 public class ProductCategory implements Serializable {

private String ID; private String code; }

//检查库存接口 public interface ICheckStorage { public boolean checkStorage(Product product, Double qty);

}

public class ACheckStorage implements ICheckStorage {} public class BCheckStorage implements ICheckStorage {} public class CCheckStorage implements ICheckStorage {}

//订单服务 public class OrderService {

OrderRepository ordRepstry; //下单 public void dispatchOrder(Order order){ if (order.checkStorage()){ //to do 设置订单状态为“下达”等操作 ordRepstry.save(order); } } public OrderService(OrderRepository ordRepstry) { super(); this.ordRepstry = ordRepstry; }

}

OrderService是repository?只是取了这么个名字吧?

>>>OrderService是repository?只是取了这么个名字吧? OrderService肯定不是repository啊,两者的角色定位不一样。

我的设计在附件里,望大家批评指正。 我的意思是楼主图中的OrderService,因为我发上帖的时候还没有看到您的帖子,非常抱歉。 model.rar


attachment:

model.rar

killer 明确了各个类的责任,赞同,但设计上我还是比较喜欢freebox 的设计, 不喜欢一堆的if-else. 在各个层传递数据时, 喜欢POJO, 所以可以再用一个类和POJO结合而达到一个所谓的充血实体.比如用代理,装饰等可以做到.

[该贴被willem于2008-06-20 15:26修改过]

final class Checkers{
	private Checkers(){}
	public static ICheckStorage getChecker(OrderItem item){
		String code=item.getProduct().getCategory().getCode();
		ICheckStorage checker=new DefaultStorage();
		if ("A".equals(code)){
			checker = new ACheckStorage();
		}
		else if ("B".equals(code)){
			checker = new BCheckStorage();
		}
		else if ("C".equals(code)){
			if (item.getDeliveryPeriod() > 30){
				checker = new ACheckStorage();
			}else{
				checker = new CCheckStorage();
			}
		}
		return checker;
	}
}
public class OrderItem implements Serializable {
	private String No; //序号
	private Product product; //产品
	private Double qty; //数量
	private long deliveryPeriod; //送货周期

	//检查库存是否足够
	public boolean isStorageEnough(){
		return Checkers.getChecker(this).checkStorage(product, qty);
	}
}
略作部分修改,望继续讨论。 上传的附件怎么下载不了呢?是不是[url]里?后面的没解释出来? 这是用上传功能上传的。 model.rar 这是编辑时显示的url,直接拿出来了。 http://www.jdon.com/jivejdon/uploadDL.jsp?type="application/octet-stream&dlname=model.rar&id=173 [该贴被freebox于2008-06-21 09:36修改过]


attachment:

model.rar