In Part 1 we saw how we can move Business Logic into Domain Objects. It was an easy example with a parent and a list of child objects. Let's look at a bit more complicated example.
Let's take for example this Business Rule:
When a Proposition is closed, no more Tasks can be added to the Phases of the Proposition.
If we build a simple system these three objects can look like this in code:
public class Proposition
{
public int Id { get; set; }
public bool IsClosed { get ; set ; }
public List<Phase> Phases { get ; set ; }
}
public class Phase
{
public int Id { get; set; }
public List<Task> Tasks { get ; set ; }
public
Proposition Proposition { get ; set ; }
public void AddTask(Task task)
{
if(Proposition.IsClosed)
{
throw new Exception("Proposition is closed.");
}
Tasks.Add(task);
}
}
public class Task
{
public string Name { get ; set ; }
}
And we can interact with Phase and Task like this:
var phase = PhaseRepository.GetById(1);
phase.AddTask(new Task());
What is the problem with this code?
The problem with the code above is that a child object (Phase) is depending on a parent object (Proposition). Why is that a problem? Because if we add another property to Proposition that has to be added to the Business Rule, we now have to edit two objects:
public class Proposition
{
...
public int Value { get; set; }
}
public class Phase
{
public void AddTask(Task task)
{
if(Proposition.IsClosed)
{
throw new Exception("Proposition is closed.");
}
if(Proposition.Value > 100)
{
throw new Exception("Propositionvalue is more than 100.");
}
Tasks.Add(task);
}
}
What is the solution?
One solution is to move this Business Rule to the Proposition object, like this:
public class Proposition
{
public int Id { get; set; }
public bool IsClosed { get ; set ; }
public List<Phase> Phases { get ; set ; }
public void AddTask(Task task,
int phaseId)
{
if(IsClosed)
{
throw new Exception("Proposition is closed.");
}
if(Value > 100)
{
throw new Exception("Propositionvalue is more than 100.");
}
Phases.Single(it => it.Id ==
phaseId ).AddTask(task);
}
}
public class Phase
{
public int Id { get; set; }
private List<Task> _tasks;
public ReadOnlyCollection<Task> ReadOnlytasks
{
get
{
return new ReadOnlyCollection<Task>(_tasks);
}
}
internal void AddTask(Task task)
{
Tasks.Add(task);
}
}
Note that AddTask in the Phase class is made internal, so it's only accessible to Proposition, and not in for example an MVC controller, or a business logic layer.
Geen opmerkingen:
Een reactie posten