Reputation: 8189
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
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
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