C#DDD填充不可变对象

时间:2010-05-25 14:24:14

标签: c#

我的域程序集中有一个不可变的Customer类。它包含以下GET属性:id,firstname和lastname。我的持久性程序集中有一个CustomerRepository类。反过来,此CustomerRepository类应使用远程web-serivce填充并返回Customer对象。

我的Customer类不包含setter属性,它包含一个私有构造函数。原因 - 我不希望UI开发人员得到错误的想法 - 他不应该能够创建或更改Customer对象。

我的问题:如何让我的CustomerRepository填充我的Customer对象。反射?或者我应该牺牲我的设计并启用公共构造函数来构建客户对象?

2 个答案:

答案 0 :(得分:3)

我同情减少API表面的愿望而不是误导来电者,但我仍然建议添加一个公共构造函数。事实上,没有setter,也没有公共SaveCustomer方法,这一点应该足以说明客户是不可变的。

如果你真的不想要一个公共构造函数,请考虑你是否真的需要单独的域和持久性程序集:有充分的理由将相关代码拆分成两个程序集,但它不应该是默认位置,不应该将名称空间替换为组织代码的主要方式(Patrick Smacchia撰写了a few great articles explaining why)。

如果将它们组合成一个程序集,则可以将构造函数设置为内部并完成它。 (正如另一位受访者提到的,InternalsVisibleTo是一个可行的替代方案 - 但它实际上只是一个黑客攻击:你的类和设计目标告诉你这些应该在一个程序集中。)

答案 1 :(得分:2)

您可能希望声明一个internal构造函数,并将三个属性作为参数。如果您的CustomerRepositoryCustomer课程不在同一个程序集中,那么您可以使用以下属性显示internal

[assembly: InternalsVisibleTo ("CustomerAssembly, PublicKey=...")]

Customer程序集中。

编辑:顺便说一下,如果你需要创建大量的对象,我不建议使用反射,因为这样做会比直接调用构造函数慢几个数量级。如果你真的必须走这条路线,我建议你添加一个静态工厂方法,你可以通过反射调用它来获得一个有效的分配器。

例如:

class Customer
{
    private Customer(...) { ... }

    private static ICustomerFactory GetCustomerFactory()
    {
        return new CustomerFactory();
    }

    private class CustomerFactory : ICustomerFactory
    {
        Customer CreateCustomer(...) { return new Customer(...); }
    }
}

public interface ICustomerFactory
{
    Customer CreateCustomer(...);
}

使用反射来调用Customer.GetCustomerFactory,从那时起,您将有一种快速有效的方法来创建Customer