跨越分析与设计的鸿沟

08-06-18 willem
如何把分析转化为设计,又如何把设计模式跟域模型结合?

这里边如何还操作,总有章可循.

各位有何高见.现在举个例比较好说明问题.

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

对A类别的产品: 不需要库存检查,可下单,

对B类别的产品: 一定要库存检查,有库存可下单,无库存不能下单

对C类别的产品:

购买该类别的客户需要选择送货周期,如果

客户要求的送货周期大于30天,是不需要检查库存(即30天后一定可以送货),如果小于30天需

要检查库存.

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

现有一个大概的设计图:

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

willem
2008-06-18 15:08
这些设计类,如果按DDD规则来分层,如何归类呢?

freebox
2008-06-18 16:16
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{...}
<p>

不知这样如何,因为我觉得是否检查是Category相关的。

[该贴被freebox于2008-06-18 16:21修改过]

willem
2008-06-18 17:41
感觉是Visitor模式. 完全不是 原来 的 Bridge 模式.思考中......

而且Visitor模式有一个不好的地方,如果我的产品类别经常变动,Visitor在这里就要改动.

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

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

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

freebox
2008-06-18 21:00
也许和您所说的原来的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{...}
<p>

[该贴被freebox于2008-06-18 21:18修改过]

willem
2008-06-19 10:40

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

这个抽出来了,比较好

banq
2008-06-19 20:15
楼上讨论很不错,Freebox的设计方案看起来还是合适恰当的。

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

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

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

killer
2008-06-20 13:11
checkStock不能放入OrderService,要坚持静态决定动态的原则。下面贴一下我的设计,不足之处,请大家指正,共同讨论改进。

//订单

public class Order implements Serializable {

private String No;

private List<OrderItem> 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;

}

}

freebox
2008-06-20 13:17
OrderService是repository?只是取了这么个名字吧?

killer
2008-06-20 14:06
>>>OrderService是repository?只是取了这么个名字吧?

OrderService肯定不是repository啊,两者的角色定位不一样。

freebox
2008-06-20 14:51
我的设计在附件里,望大家批评指正。

我的意思是楼主图中的OrderService,因为我发上帖的时候还没有看到您的帖子,非常抱歉。

model.rar


attachment:


model.rar

willem
2008-06-20 15:24
killer 明确了各个类的责任,赞同,但设计上我还是比较喜欢freebox 的设计, 不喜欢一堆的if-else.

在各个层传递数据时, 喜欢POJO, 所以可以再用一个类和POJO结合而达到一个所谓的充血实体.比如用代理,装饰等可以做到.

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

freebox
2008-06-20 16: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);
	}
}
<p>

略作部分修改,望继续讨论。

上传的附件怎么下载不了呢?是不是[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

猜你喜欢
3Go 1 2 3 下一页