using System; using HRSystem.Domain.Common; namespace HRSystem.Domain.Entities { public class Employee : Entity { private string _name; private string _payrollNumber; private DateTime _joinedOn; public virtual string Name { get { return _name; } set { _name = value; } } public virtual string PayrollNumber { get { return _payrollNumber; } set { _payrollNumber = value; } } public virtual DateTime JoinedOn { get { return _joinedOn; } set { _joinedOn = value; } } public static Employee Create(string role, string name, string payrollNumber, string department) { Employee employee = null; if (role == "Manager") { employee = new Manager(); Manager manager = employee as Manager; manager.Department = department; manager.BecameManagerOn = DateTime.Now; } else { employee = new Employee(); } employee.Name = name; employee.PayrollNumber = payrollNumber; employee.JoinedOn = DateTime.Now; return employee; } public void Amend(string name, string payrollNumber, DateTime joinedOn) { _name = name; _payrollNumber = payrollNumber; _joinedOn = joinedOn; } } }And here is the code for the Manager entity:
using System; namespace HRSystem.Domain.Entities { public class Manager : Employee { private string _department; private DateTime _becameManagerOn; public virtual string Department { get { return _department; } set { _department = value; } } public DateTime BecameManagerOn { get { return _becameManagerOn; } set { _becameManagerOn = value; } } } }Please note that these both ultimately inherit from the Entity class, which should be familliar to any regular users of NHibernate:
using System; using HRSystem.Domain.Entities; namespace HRSystem.Domain.Common { public class Entity { protected long? _id; protected int? _hashCode; public virtual long? Id { get { return _id; } set { _id = value; } } public override bool Equals(object obj) { Entity other = obj as Entity; if (other == null) return false; if (!other.Id.HasValue && !_id.HasValue) return other == this; if (!other.Id.HasValue || !_id.HasValue) return false; return other.Id.Value == _id.Value; } public override int GetHashCode() { if (_hashCode.HasValue) return _hashCode.Value; if (!_id.HasValue) { _hashCode = base.GetHashCode(); return _hashCode.Value; } return _id.GetHashCode(); } } }So how do we model the promotion of an Employee to a Manager? Perhaps a method on the Employee called Promote, like the following code. Note that in order to change the Employee to a Manager, the extra parameters that a Manager has need to be supplied:
public void Promote(string department) { //Make the class I'm in a Manager, not an Employee... }The problem with this is that method would somehow have to change the type of the class it belongs to. This is not possible, not in C#, not in Java, not in any OO language.
In Domain Driven Design, Eric Evans makes the case for factory methods. The arguments is that on a car, the methods represent things like the accelerator or brake, which change the state of the car. However, the car does not carry around the ability to build itself - that is done in a factory. But what if we really wanted to change the state of the car? I'm talking tuned engine, new alloys, new paint job, new ICE etc. Unfortunately my car doesn't have a button for that - I have to take it to the garage. When it comes back, it's hardly the same car. The car entity could have a myRide.Pimp() method, and what comes back from that is a whole new car.
For the Employee, the method would look something like this:
public virtual Manager Promote(string department) { Manager manager = new Manager(); manager.Id = _id; manager.Name = _name; manager.PayrollNumber = _payrollNumber; manager.JoinedOn = _joinedOn; manager.Department = department; manager.BecameManagerOn = DateTime.Now; return manager; }The code to promote an employee to the manager of ICT would look like this:
Manager manager = employee.Promote("ICT");I'm not completely sure that Promote(string department) is the quite the right name for this, it should possibly be something like 'GetPromotedVersion(string department)', but I feel it is acceptable in this instance.
The next stage is how to load the Employee and then persist it as a Manager, which I will cover in the next post.
No comments:
Post a Comment