tags:

views:

62

answers:

2

Hi

I have a immutable Customer class in my domain assembly. It contains the following GET properties : id, firstname and lastname. I have a CustomerRepository class in my persistence assembly. In turn, this CustomerRepository class should populate and return a Customer object using a remote web-serivce.

My Customer class contains no setter properties and it contains a private constructor. The reason - I dont want the UI developer to get the wrong idea - He should not be able to create or change a Customer object.

My question: How do I get my CustomerRepository to populate my Customer object. Reflection? Or should I sacrifice my design and enable a public constructor for constructing the customer object?

+2  A: 

I sympathize with the desire to reduce the surface of the API and not mislead callers, but I still recommend adding a public constructor. The fact that there are no setters and no public SaveCustomer method should make it clear enough that the customer is immutable.

If you really don't want a public constructor, consider whether you really need separate domain and persistence assemblies: there are good reasons to split related code into two assemblies, but it shouldn't be the default position and shouldn't replace namespaces as the primary way of organizing code (Patrick Smacchia has written a few great articles explaining why).

If you combine them into a single assembly, you can just make the constructor internal and be done with it. (As another respondent mentioned, InternalsVisibleTo is a viable alternative - but it's really just a hack: your classes and design goals are telling you these should be in a single assembly.)

Jeff Sternal
Should the constructor set the id field aswell?
Russel
@Russel - yes, I think so. If someone is tempted to create a bogus customer with a made-up identifier (which doesn't seem very likely), they'll quickly learn the error of their ways. What's more, a UI developer or someone writing unit tests will want to be able to test their code even when the database isn't available, so they need to be able to construct complete instances.
Jeff Sternal
I hear what you are saying...but what if I use reflection to construct fake Customer objects to test against? Then I would have CustomerObjectMother or something to construct fake Customer objects.
Russel
Sure - if you're a glutton for punishment, you're welcome to use reflection. ;) But in all seriousness, making the constructor private solves a problem (preventing people from mistakenly creating customer objects on their own) that is trivial to correct (if it even ever happens) - and makes your life much harder in myriad ways by obligating you to write tons of code to do something that should be very simple (test dependent collaborators).
Jeff Sternal
+1  A: 

You might want to declare an internal constructor, with your three properties as parameters. If your CustomerRepository does not live in the same assembly as your Customer class, then you can make your internals visible by using the following attribute:

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

in the Customer assembly.

Edit: By the way, I would not recommend using reflection if you need to create lots of objects, because doing so will be orders of magnitude slower than direct calls to constructors. If you really have to go that route, I'd recommend adding a static factory method which you can call through reflection in order to get an efficient allocator.

For instance:

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(...);
}

Use reflection to call Customer.GetCustomerFactory and from then on, you'll have a fast and efficient way of creating your Customers.

Pierre