2011-03-31 57 views
1

我想对下面的域驱动设计提出一些建议和批评。我在下面包含了伪代码。真正的代码将具有封装的属性。域名驱动设计评判

问题

我唯一担心的是,它似乎是贫血。

步骤

  1. 创建与价值观的新请求
  2. 被请求批准?
    1. 如果是的话,显示值
    2. 如果没有,表明没有批准
    3. 原因

enum UnitedStatesState { 
    ALABAMA, 
    //... 
    CALIFORNIA, 
    //... 
    MAINE, 
    //... 
    WASHINGTON 
} 

class License { 
    int id; 
    String name; 

    //enum of state that the license is applicable in 
    UnitedStatesState state; 
} 

class LicenseRequest { 
    //the name of the person making the request 
    String name; 

    //enum of state to which the user is requesting a license in 
    UnitedStatesState state; 

    LicenseResponse submit() 
    { 
    //TODO: move creation of the rules out of this class 
    RuleGroup<LicenseRequest> ruleGroup = new RuleGroup<>(); 
    ruleGroup.add(new StateExclusionLicenseRequestRule(UnitedStatesState.MAINE)); 

    boolean approved = ruleGroup.execute(this); 
    if(approved) { 
     License license = createLiscense(request); 
     return new ApprovedLicenseResponse(license); 
    } else { 
     DeniedLicenseResponse response = new DeniedLicenseResponse(); 
     response.rules = newArrayList(ruleGroup); 
     return response; 
    } 
    } 

    //TODO: move create license out of Request. maybe a factory class? 
    private License createLicense() 
    { 
    License license = LicenseIdGenerator.generate(this.state); 
    license.name = this.name; 
    license.state = this.state; 
    save(license); 
    return license; 
    } 
} 

//visitor for the rule 
interface Rule<T> { 
    public boolean execute(T o); 
    public List<String> getMessages(); 
} 

//rule that auto denies when the request is made in an excluded state 
class StateExclusionLicenseRequestRule : Rule<LicenseRequest> { 
    public List<String> getMessages(); 
    UnitedStatesState excludedState; 
    public boolean execute(LicenseRequest request) { 
    if(request.state == excludedState) 
    { 
     messages.add("No license for " + request.state + " is available at this time."); 
     return false; 
    } 
    return true; 
    } 
} 

//rule that groups all other rules 
class RuleGroup<T> : Rule<T> { 
    public void addRule(Rule<T> rule); 
    public List<Rule<T>> getFailedRules(); 

    public List<String> getMessages() { 
    List<String> messages = new ArrayList<>(); 
    for(Rule<T> rule : rules) { 
     messages.addAll(rule.getMessages()); 
    } 
    return messages; 
    } 

    public boolean execute(T o) { 
    List<Rule<T>> failedRules = new ArrayList<>(rules.size()); 
    for(Rule<T> rule : rules) { 
     boolean approve = rule.execute(o); 
     if(!approve) { 
     failedRules.add(rule); 
     } 
    } 
    return !failedRules.isEmpty(); 
    } 
} 

interface LicenseResponse { 
    boolean approved; 
} 

class ApprovedLicenseResponse : LicenseResponse { 
    License license; 
} 
class DeniedLicenseResponse : LicenseResponse { 
    private List<Rule<LicenseRequest>> rules; 

    public List<String> getMessages() 
    { 
    List<String> messages = new ArrayList<>(); 
    for(Rule<LicenseRequest> rule : rules) { 
     messages.addAll(rule.getMessages()); 
    } 
    return messages; 
    } 
} 

示例代码

request = new Request(name: 'Test', state: UnitedStatesState.CALIFORNIA) 
response = request.submit() 
if(response.approved) 
{ 
    out('Your request is approved'); 
    out('license id = ' + reponse.id); 
} 
else 
{ 
    out('Your request was denied'); 
    for(String message : response.messages) 
    { 
    out(message); 
    } 
} 

更新1:背景

这只是我想要实现的一个模拟。这是一个简单的系统,用户将信息输入到自己的表格中,并且他们被批准或拒绝许可证。批准后,可以打印证书。

为了举例,唯一的规则是缅因州的许可证申请被拒绝。

更新2:重构规则和删除处理程序

我做了一些修改,以上面的例子。删除处理程序并将所有代码移动到LicenseRequest。我也将批准/拒绝的规则提交给实施vistor模式的课程。

+1

看来,我认为您正在更换缺少的重要经营理念/ s的程序, “域之外的”Handler“概念。 – 2011-04-01 00:17:36

+1

给我们一些关于您尝试解决的问题的简短介绍,ddd在没有上下文的情况下无法正常工作。给我们一些洞察什么使用这个和为什么。 – 2011-04-02 07:40:11

+0

@ kyri-sarantakos - 我已经添加了一些背景。如果您需要更多信息,请告诉我。 – 2011-04-04 13:42:50

回答

2

不幸的是一些更相关的代码没有显示,但我会考虑看看哪些代码可以推入LicenseRequest。特别是,LicenseRequest可能会创建License而不是处理程序(可能通过给它ID)。如果仅在创建批准的许可证时使用LicenseRequest的属性,情况尤其如此。然后这些不必与吸气剂一起暴露。

我也有determineApproval(可能有其他名字)直接创建响应而不是传递可写消息列表(仅用于失败)。

您应该寻找的气味是Feature Envy。特别是使用LicenseLicenseRequest的数据进行的任何计算都应该检查以确定是否应该在这些类中进行计算。

数据对象(特别是不可变的数据对象)有一个目的,但你是正确的担心。

+0

我已按照您的建议进行最新更新。我是否改变了你所想的部分? – 2011-04-04 14:36:28

0

国家应该是ValueObjects的可扩展性。例如,当你需要将一个州的缩写等同于它的名字时会发生什么?

它也看起来像你的设计没有真正的聚合根。没有许可证的LicenseRequest是无意义的吗?在这种情况下,应该通过许可证(或许可证服务)处理,而不是直接由调用代码(可能是Web服务器,控制台应用程序等)处理。

因此,对于伪代码会像

var license = licenseFactory.NewLicense(); 
response = license.Request(name, state) 

更有意义?当您拥有多种类型的许可证时会发生什么情况,比如Commercial Driver's?

另外,对于规则,而不是一个命令模式(执行),你可以通过有规则的规格得到了清晰的解决方案 - https://en.wikipedia.org/wiki/Specification_pattern