coding4fun
coding4fun

Reputation: 8189

Populating your domain objects with data correctly?

I'm having trouble understanding how to design my domain objects correctly. The issue i keep grappling with is how to populate my domain objects with data. The examples i've found have been to trivial to really help me out. I've tried a variety of methods but i don't love any of them. Say you have a large set of data you need to pass into your class so you bundle it in a POCO.

My first direction (pass data into the constructor):

public class MyClass
{
    private readonly ICalculator _calculator;
    private readonly MyClassDataPOCO _data;

    public MyClass(ICalculator _calculator, MyClassDataPOCO data)
    {
        this._calculator = _calculator;
        _data = data

This doesn't work out well because then your IOC containers can't automatically initialize your classes.

Second Direction (pass data into the operation):

public class MyClass
{
    private readonly ICalculator _calculator;

    public MyClass(ICalculator _calculator)
    {
        this._calculator = _calculator;
    }

    public decimal CalculateComplicatedValue1(MyClassDataPOCO data)
    {

    }

    public decimal CalculateComplicatedValue2(MyClassDataPOCO data)
    {

    }

I didn't like this for a variety of reasons

  1. Your class become nothing more than instance functions (not really classes). They only have behavior and not data.
  2. Your entrusting your client to your data. Doesn't seem like a smart idea. I'm sure you would eventually run into mutated state problems.

Third Direction (only allow you're class to be created through a static factory method):

public class MyClass
{
    private readonly ICalculator _calculator;
    private MyClassDataPOCO _data;

    private MyClass(ICalculator _calculator)
    {
        this._calculator = _calculator;
    }

    public static MyClass Create(MyClassDataPOCO data)
    {
        return Create(_container.GetInstance<ICalculator>(), data);
    }


    public static MyClass Create(ICalculator calculator, MyClassDataPOCO data)
    {
        //do some input validation here

        var myReturn = new MyClass(calculator);
        myReturn._data = data;
        return myReturn;
    }

I guess out of all the options i like this one the best. The only thing i don't like is having to have two create functions so it can be unit tested (so i can inject ICalculator).

The only option i didn't try was property injection because id didn't think it was a good idea to inject your data in through properties.

Upvotes: 1

Views: 241

Answers (1)

MikeSW
MikeSW

Reputation: 16348

You design a domain object (DO) based on business concept and use cases. From my experience, this means your objects should be quite slim. The DO is implemented based on concept definition. A business use case is implemented in a service (can be app service, can be domain service, it depends on the context) which will use the DO in order to update stuff.

When I design an object, I just think of what input I need for what behaviour. All objects should have an initial state so you pass a DTO (everything is a POCO, we don't care about persistence here) with initial values. Actually, it's the same for every method.

About persistence, since I'm using CQRS, I only care about save/get an object. Personally I prefer to json the object (if I don't use event sourcing) so save=serialize, get=deserialize. About encapsulation, you can configure the json serializer to work with private properties and basically having private properties is the only compromise you make.

As I've said before, a use case is implemented as a service, so in your scenario, MyClass is actually a service, not a DO. As a thumb rule, a DO contains only data and behaviour which help define the object. CalculateComplicatedValue doesn't look like a part of a concept, but it does look like a use case therefore a service.

You don't need a factory here, instantiating a DO is usually straightforward, however a service usually is instantiated by a DI Container, because in most cases a service does use other services (like a repository or a validator).

Upvotes: 2

Related Questions