DDD领域驱动设计之领域基础设施层

时间:2022-08-31 18:17:03

1、DDD领域驱动设计实践篇之如何提取模型

2、DDD领域驱动设计之聚合、实体、值对象

其实这里说的基础设施层只是领域层的一些接口和基类而已,没有其他的如日子工具等代码,仅仅是为了说明领域层的一些基础问题

1、领域事件简单实现代码,都是来至ASP.NET设计模式书中的代码

namespace DDD.Infrastructure.Domain.Events
{
public interface IDomainEvent
{
}
}
namespace DDD.Infrastructure.Domain.Events
{
public interface IDomainEventHandler<T> : IDomainEventHandler
where T : IDomainEvent
{
void Handle(T e);
}

public interface IDomainEventHandler
{

}

}
namespace DDD.Infrastructure.Domain.Events
{
public interface IDomainEventHandlerFactory
{
IEnumerable<IDomainEventHandler<T>> GetDomainEventHandlersFor<T>(T domainEvent)
where T : IDomainEvent;
}

}
namespace DDD.Infrastructure.Domain.Events
{
public class StructureMapDomainEventHandlerFactory : IDomainEventHandlerFactory
{
public IEnumerable<IDomainEventHandler<T>> GetDomainEventHandlersFor<T>
(T domainEvent) where T : IDomainEvent
{
return ObjectFactory.GetAllInstances<IDomainEventHandler<T>>();
}
}

}
namespace DDD.Infrastructure.Domain.Events
{
public static class DomainEvents
{
public static IDomainEventHandlerFactory DomainEventHandlerFactory { get; set; }

public static void Raise<T>(T domainEvent) where T : IDomainEvent
{
var handlers = DomainEventHandlerFactory.GetDomainEventHandlersFor(domainEvent);
foreach (var item in handlers)
{
item.Handle(domainEvent);
}
}
}
}

2、领域层接口代码,很多都是来至MS NLayer代码和google code

 

namespace DDD.Infrastructure.Domain
{
public interface IEntity<out TId>
{
TId Id { get; }
}
}
namespace DDD.Infrastructure.Domain
{
public interface IAggregateRoot : IAggregateRoot<string>
{
}

public interface IAggregateRoot<out TId> : IEntity<TId>
{
}
}
namespace DDD.Infrastructure.Domain
{
public abstract class EntityBase : EntityBase<string>
{
protected EntityBase()
:this(null)
{
}

protected EntityBase(string id)
{
this.Id = id;
}

public override string Id
{
get
{
return base.Id;
}
set
{
base.Id = value;
if (string.IsNullOrEmpty(this.Id))
{
this.Id = EntityBase.NewId();
}
}
}

public static string NewId()
{
return Guid.NewGuid().ToString("N");
}
}

public abstract class EntityBase<TId> : IEntity<TId>
{
public virtual TId Id
{
get;
set;
}

public virtual IEnumerable<BusinessRule> Validate()
{
return new BusinessRule[] { };
}

public override bool Equals(object entity)
{
return entity != null
&& entity is EntityBase<TId>
&& this == (EntityBase<TId>)entity;
}

public override int GetHashCode()
{
return this.Id.GetHashCode();
}

public static bool operator ==(EntityBase<TId> entity1, EntityBase<TId> entity2)
{
if ((object)entity1 == null && (object)entity2 == null)
{
return true;
}

if ((object)entity1 == null || (object)entity2 == null)
{
return false;
}

if (entity1.Id.ToString() == entity2.Id.ToString())
{
return true;
}

return false;
}

public static bool operator !=(EntityBase<TId> entity1, EntityBase<TId> entity2)
{
return (!(entity1 == entity2));
}
}

}
namespace DDD.Infrastructure.Domain
{
public interface IRepository<TEntity> : IRepository<TEntity, string>
where TEntity : IAggregateRoot
{
}

public interface IRepository<TEntity, in TId>
where TEntity : IAggregateRoot<TId>
{
void Modify(TEntity entity);
void Add(TEntity entity);
void Remove(TId id);

IQueryable<TEntity> Where(Expression<Func<TEntity, bool>> predicate);
IQueryable<TEntity> All();
TEntity Find(TId id);
}
}
namespace DDD.Infrastructure.Domain
{
public class BusinessRule
{
private string _property;
private string _rule;

public BusinessRule(string rule)
{
this._rule = rule;
}

public BusinessRule(string property, string rule)
{
this._property = property;
this._rule = rule;
}

public string Property
{
get { return _property; }
set { _property = value; }
}

public string Rule
{
get { return _rule; }
set { _rule = value; }
}
}

}
namespace DDD.Infrastructure.Domain
{
/// <summary>
/// Abstract Base Class for Value Objects
/// Based on CodeCamp Server codebase http://code.google.com/p/codecampserver
/// </summary>
/// <typeparam name="TObject">The type of the object.</typeparam>
[Serializable]
public class ValueObject<TObject> : IEquatable<TObject> where TObject : class
{

/// <summary>
/// Implements the operator ==.
/// </summary>
/// <param name="left">The left.</param>
/// <param name="right">The right.</param>
/// <returns>The result of the operator.</returns>
public static bool operator ==(ValueObject<TObject> left, ValueObject<TObject> right)
{
if (ReferenceEquals(left, null))
return ReferenceEquals(right, null);

return left.Equals(right);
}

/// <summary>
/// Implements the operator !=.
/// </summary>
/// <param name="left">The left.</param>
/// <param name="right">The right.</param>
/// <returns>The result of the operator.</returns>
public static bool operator !=(ValueObject<TObject> left, ValueObject<TObject> right)
{
return !(left == right);
}

/// <summary>
/// Equalses the specified candidate.
/// </summary>
/// <param name="candidate">The candidate.</param>
/// <returns>
/// true if the current object is equal to the <paramref name="candidate"/> parameter; otherwise, false.
/// </returns>
public override bool Equals(object candidate)
{
if (candidate == null)
return false;

var other = candidate as TObject;

return Equals(other);
}

/// <summary>
/// Indicates whether the current object is equal to another object of the same type.
/// </summary>
/// <param name="other">An object to compare with this object.</param>
/// <returns>
/// true if the current object is equal to the <paramref name="other"/> parameter; otherwise, false.
/// </returns>
public virtual bool Equals(TObject other)
{
if (other == null)
return false;

Type t = GetType();

FieldInfo[] fields = t.GetFields(BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public);

foreach (FieldInfo field in fields)
{
object otherValue = field.GetValue(other);
object thisValue = field.GetValue(this);

//if the value is null...
if (otherValue == null)
{
if (thisValue != null)
return false;
}
//if the value is a datetime-related type...
else if ((typeof(DateTime).IsAssignableFrom(field.FieldType)) ||
((typeof(DateTime?).IsAssignableFrom(field.FieldType))))
{
string dateString1 = ((DateTime)otherValue).ToLongDateString();
string dateString2 = ((DateTime)thisValue).ToLongDateString();
if (!dateString1.Equals(dateString2))
{
return false;
}
continue;
}
//if the value is any collection...
else if (typeof(IEnumerable).IsAssignableFrom(field.FieldType))
{
IEnumerable otherEnumerable = (IEnumerable)otherValue;
IEnumerable thisEnumerable = (IEnumerable)thisValue;

if (!otherEnumerable.Cast<object>().SequenceEqual(thisEnumerable.Cast<object>()))
return false;
}
//if we get this far, just compare the two values...
else if (!otherValue.Equals(thisValue))
return false;
}

return true;
}

/// <summary>
/// Serves as a hash function for a particular type.
/// </summary>
/// <returns>
/// A hash code for the current <see cref="T:System.Object"/>.
/// </returns>
public override int GetHashCode()
{
IEnumerable<FieldInfo> fields = GetFields();

const int startValue = 17;
const int multiplier = 59;

int hashCode = startValue;

foreach (FieldInfo field in fields)
{
object value = field.GetValue(this);

if (value != null)
hashCode = hashCode * multiplier + value.GetHashCode();
}

return hashCode;
}

/// <summary>
/// Gets the fields.
/// </summary>
/// <returns>FieldInfo collection</returns>
private IEnumerable<FieldInfo> GetFields()
{
Type t = GetType();

var fields = new List<FieldInfo>();

while (t != typeof(object))
{
fields.AddRange(t.GetFields(BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public));

t = t.BaseType;
}

return fields;
}

}
}