Generic Entity and Value Object in DDD

In the Domain Layer of DDD architecture, it's necessary to create generic entity and value object.

Generic Entity :


public interface IEntity<t> where T : class
{
long ID { get; set; }
bool IsTransient();
bool Equals(object obj);
bool Equals(Entity<t> other);
int GetHashCode();
string ToString();
}
[Serializable]
public abstract class Entity : IEntity where T : class
{
private int? _oldHashCode;
public virtual long ID { get; set; }
public virtual bool IsTransient()
{
return ID.Equals(0);
}
public virtual bool Equals(Entity other)
{
if (ReferenceEquals(this, other))
return true;
if (other == null || !(other is T))
return false;
if (!IsTransient() && !other.IsTransient() && ID.Equals(other.ID))
return true;
return IsTransient() && other.IsTransient();
}

public override bool Equals(object obj)
{
var compareTo = obj as Entity;
return Equals(compareTo);
}
public override int GetHashCode()
{
unchecked
{
if (_oldHashCode.HasValue)
return _oldHashCode.Value;
if (IsTransient())
{
_oldHashCode = base.GetHashCode();
return _oldHashCode.Value;
}
return ID.GetHashCode();
}
}
public override string ToString()
{
return GetType().FullName + "#" + ID;
}
public static bool operator ==(Entity left, Entity right)
{
return Equals(left, right);
}

public static bool operator !=(Entity left, Entity right)
{
return !Equals(left, right);
}
}




Generic ValueObject

public interface IValueObject<t> where T : class
{
bool IsTransient();
bool Equals(ValueObject<t> other);
bool Equals(object obj);
int GetHashCode();
string ToString();
}

[Serializable]
public abstract class ValueObject<t> : IEquatable<t>, IValueObject<t> where T : class
{
private int? _oldHashCode;
public abstract bool IsTransient();
public virtual bool Equals(T other)
{
var compareTo = other as ValueObject<t>;

return Equals(compareTo);
}
public virtual bool Equals(ValueObject<t> other)
{
if (ReferenceEquals(this, other))
return true;

if (ReferenceEquals(null, other) || !GetType().Equals(other.GetType()))
return false;

if (!IsTransient() &amp;&amp; !other.IsTransient() &amp;&amp; PropertiesEquals(other))
return true;

return IsTransient() &amp;&amp; other.IsTransient();
}
public override bool Equals(object obj)
{
var compareTo = obj as ValueObject<t>;

return Equals(compareTo);
}

public override int GetHashCode()
{
unchecked
{
if (_oldHashCode.HasValue)
return _oldHashCode.Value;

if (IsTransient())
{
_oldHashCode = base.GetHashCode();
return _oldHashCode.Value;
}

return PropertiesGetHashCode();
}
}

public override string ToString()
{
return GetType().FullName;
}

protected abstract bool PropertiesEquals(ValueObject<t> obj);
protected abstract int PropertiesGetHashCode();

public static bool operator ==(ValueObject<t> left, ValueObject<t> right)
{
return Equals(left, right);
}

public static bool operator !=(ValueObject<t> left, ValueObject<t> right)
{
return !Equals(left, right);
}

public static bool IsTransient<tentity>(IEntity<tentity> entity) where TEntity : class
{
return entity == null || entity.IsTransient();
}
}

Example of Value Object :


public class Address : ValueObject<address>
{
...
public override bool IsTransient()
{
return StreetAddress == null &amp;&amp; City == null &amp;&amp; ZipCode == null;
}

protected override bool PropertiesEquals(ValueObject<address> obj)
{
Address adr = obj as Address;
if (adr != null)
{
return StreetAddress == adr.StreetAddress &amp;&amp; City == adr.City
&amp;&amp; ZipCode == adr.ZipCode;
}
return false;
}

protected override int PropertiesGetHashCode()
{
return (StreetAddress ?? string.Empty).GetHashCode() ^ (City ?? string.Empty).GetHashCode()
^ (ZipCode ?? string.Empty).GetHashCode() ;
}
}

No comments:

Post a Comment