上一篇介绍了值对象的基本概念,获得了一些朋友的支持,另外也有一些朋友提出了不一样意见。这实际上是很天然的事情,设计原本就充满了各类可能性,没有绝对正确的作法,只有更好的实践。可是设计与实践的好与坏,对于不一样的人,以及处于不一样的环境都有不一样的诠释,这是一个仁者见仁,智者见智的问题。DDD很是抽象,以致于它的每个概念,对于不一样的人都有不一样的见解,更况且基于DDD的.Net实践,就更难分辨哪个用法更标准、更正宗。架构
我对DDD的认识虽然还很肤浅,用得也很山寨,但这可能更加适合初步接触DDD的朋友。仍是那句老话,你不是搞学术研究的,你并不须要挖掘DDD的学术价值,而是要把它切实的用到你的项目上,并产生回报。你不该该问对或错,而应该多看看哪些东西对你真正起做用,一方面须要多学习DDD理论知识,另外一方面能够多参考其它人的用法,并琢磨出一套适合本身习惯的架构。特别是初学DDD的朋友,这一点更加剧要,DDD水很深,盲目的采用某些你搞不懂的技术,只会增长负担。你也不须要把DDD全部东西都用起来,使用DDD不是为了赶时髦,若是某些东西让你感受复杂,你先了解下就能够了,把搞懂的东西加入你的工具箱,而后项目上慢慢体验,时间稍长,你就能产生突破并从中受益。但你若是人云亦云,把注意力放到纯概念和一些名词术语上,把别人的经验生搬硬套到本身的项目,因为别人的思想你可能没有真正搞懂,另外别人的项目需求、团队水平、所用技术可能和你都不一样,这样可能致使你维护了一个庞大的架构,但却没有捞到一丁点好处。框架
我这个系列重点不在DDD,而是如何搭建本身的应用程序框架。介绍DDD分层架构只是保证本系列的完整性,因此我不会很是详细的介绍。另外不少朋友迫切须要示例,我在此回复一下,本系列前期主要进行框架建设,包括一些公共操做类和层超类型,待底子打牢以后,我会向你们展现个人山寨DDD用法,以及如何经过应用程序框架快速开发项目。之因此不上来就搞一堆代码,是但愿你经过这个系列能真正受益,你不只须要知道框架怎么用,更须要知道这玩意是怎么弄出来的,以及重要代码的思考和演化过程。因此我写得可能很是啰嗦,我但愿.Net初学者也能看懂。个人时间比较有限,更新时间不会太快,不过只要有人愿意继续看,我会坚持写完它。ide
下面回到正文上来,本篇将完成DDD值对象的层超类型开发,全部代码都从网上搜集整理,若是你们有更好的请把你的代码发上来供你们参考,另外最好详细介绍你的代码为什么更好,以避免你们凭空瞎猜。工具
首先,在Util.Domains类库中建立一个名为ValueObjectBase的抽象类。性能
考虑值对象的相等性测试,怎样才能认为两个值对象是相等的?这能够经过比较两个值对象的全部属性值都相等来判断,换句话说,两个值对象有任何一个属性值不一样,都不相等。咱们须要重写Equals、GetHashCode 、==、!=这几个方法或运算符。单元测试
在相等性比较中,咱们能够经过反射来获取全部属性,并一一比较,以测试相等性。另外,GetHashCode将各属性值的哈希码使用简单的异或操做计算出来。若是以为性能很差,子类能够重写相关实现。学习
另外,值对象有时候须要建立一个副本,能够增长一个克隆方法Clone,采用浅表复制进行建立,因为值对象不可变,因此不一样的值对象共享相同的属性值就不是什么问题。为了让Clone更加好用,可让它建立出强类型的值对象,而不是一个object,这须要将值对象层超类型修改成泛型,将值对象做为泛型参数传递到基类。测试
另外,前面介绍的实体状态输出和验证方法对值对象一样适用,因此须要在实体和值对象层超类型之上再增长一个基类,命名为DomainBase。ui
因为值对象层超类型比较简单,我就简要介绍到这,下面是相关代码,若有疑问请留言。this
测试样例Address类代码以下,为了简单,我只留下两个属性。
namespace Util.Domains.Tests.Samples { /// <summary>
/// 地址 /// </summary>
public class Address : ValueObjectBase<Address> { /// <summary>
/// 初始化地址 /// </summary>
/// <param name="city">城市</param>
/// <param name="street">街道</param>
public Address( string city, string street ) { City = city; Street = street; } /// <summary>
/// 城市 /// </summary>
public string City { get; private set; } /// <summary>
/// 街道 /// </summary>
public string Street { get; private set; } } }
值对象单元测试类ValueObjectBaseTest代码以下。
using Microsoft.VisualStudio.TestTools.UnitTesting; using Util.Domains.Tests.Samples; namespace Util.Domains.Tests { /// <summary>
/// 值对象测试 /// </summary>
[TestClass] public class ValueObjectBaseTest { /// <summary>
/// 地址1 /// </summary>
private Address _address1; /// <summary>
/// 地址2 /// </summary>
private Address _address2; /// <summary>
/// 地址3 /// </summary>
private Address _address3; /// <summary>
/// 测试初始化 /// </summary>
[TestInitialize] public void TestInit() { _address1 = new Address("a","b"); _address2 = new Address( "a", "b" ); _address3 = new Address( "1", "" ); } /// <summary>
/// 测试对象相等性 /// </summary>
[TestMethod] public void TestEquals() { Assert.IsFalse( _address1.Equals( null ) ); Assert.IsFalse( _address1 == null ); Assert.IsFalse( null == _address1 ); Assert.IsFalse( _address1.Equals(new Test()) ); Assert.IsTrue( _address1.Equals( _address2 ), "_address1.Equals( _address2 )" ); Assert.IsTrue( _address1 == _address2, "_address1 == _address2" ); Assert.IsFalse( _address1 != _address2, "_address1 != _address2" ); Assert.IsFalse( _address1 == _address3, "_address1 == _address3" ); } /// <summary>
/// 测试哈希 /// </summary>
[TestMethod] public void TestGetHashCode() { Assert.IsTrue( _address1.GetHashCode() == _address2.GetHashCode(), "_address1.GetHashCode() == _address2.GetHashCode()" ); Assert.IsFalse( _address1.GetHashCode() == _address3.GetHashCode(), "_address1.GetHashCode() == _address3.GetHashCode()" ); } /// <summary>
/// 测试克隆 /// </summary>
[TestMethod] public void TestClone() { _address3 = _address1.Clone(); Assert.IsTrue( _address1 == _address3 ); } } }
DomainBase代码以下。
using System.Collections.Generic; using System.Text; using Util.Validations; namespace Util.Domains { /// <summary>
/// 领域层顶级基类 /// </summary>
public abstract class DomainBase { #region 构造方法
/// <summary>
/// 初始化领域层顶级基类 /// </summary>
protected DomainBase() { _rules = new List<IValidationRule>(); _handler = new ValidationHandler(); } #endregion
#region 字段
/// <summary>
/// 描述 /// </summary>
private StringBuilder _description; /// <summary>
/// 验证规则集合 /// </summary>
private readonly List<IValidationRule> _rules; /// <summary>
/// 验证处理器 /// </summary>
private IValidationHandler _handler; #endregion
#region ToString(输出领域对象的状态)
/// <summary>
/// 输出领域对象的状态 /// </summary>
public override string ToString() { _description = new StringBuilder(); AddDescriptions(); return _description.ToString().TrimEnd().TrimEnd( ',' ); } /// <summary>
/// 添加描述 /// </summary>
protected virtual void AddDescriptions() { } /// <summary>
/// 添加描述 /// </summary>
protected void AddDescription( string description ) { if ( string.IsNullOrWhiteSpace( description ) ) return; _description.Append( description ); } /// <summary>
/// 添加描述 /// </summary>
protected void AddDescription<T>( string name, T value ) { if ( string.IsNullOrWhiteSpace( value.ToStr() ) ) return; _description.AppendFormat( "{0}:{1},", name, value ); } #endregion
#region SetValidationHandler(设置验证处理器)
/// <summary>
/// 设置验证处理器 /// </summary>
/// <param name="handler">验证处理器</param>
public void SetValidationHandler( IValidationHandler handler ) { if ( handler == null ) return; _handler = handler; } #endregion
#region AddValidationRule(添加验证规则)
/// <summary>
/// 添加验证规则 /// </summary>
/// <param name="rule">验证规则</param>
public void AddValidationRule( IValidationRule rule ) { if ( rule == null ) return; _rules.Add( rule ); } #endregion
#region Validate(验证)
/// <summary>
/// 验证 /// </summary>
public virtual void Validate() { var result = GetValidationResult(); HandleValidationResult( result ); } /// <summary>
/// 获取验证结果 /// </summary>
private ValidationResultCollection GetValidationResult() { var result = ValidationFactory.Create().Validate( this ); Validate( result ); foreach ( var rule in _rules ) result.Add( rule.Validate() ); return result; } /// <summary>
/// 验证并添加到验证结果集合 /// </summary>
/// <param name="results">验证结果集合</param>
protected virtual void Validate( ValidationResultCollection results ) { } /// <summary>
/// 处理验证结果 /// </summary>
private void HandleValidationResult( ValidationResultCollection results ) { if ( results.IsValid ) return; _handler.Handle( results ); } #endregion } }
ValueObjectBase代码以下。
using System; using System.Linq; namespace Util.Domains { /// <summary>
/// 值对象 /// </summary>
/// <typeparam name="TValueObject">值对象类型</typeparam>
public abstract class ValueObjectBase<TValueObject> : DomainBase, IEquatable<TValueObject> where TValueObject : ValueObjectBase<TValueObject> { #region Equals(相等性比较)
/// <summary>
/// 相等性比较 /// </summary>
public bool Equals( TValueObject other ) { return this == other; } /// <summary>
/// 相等性比较 /// </summary>
public override bool Equals( object other ) { return Equals( other as TValueObject ); } #endregion
#region ==(相等性比较)
/// <summary>
/// 相等性比较 /// </summary>
public static bool operator ==( ValueObjectBase<TValueObject> valueObject1, ValueObjectBase<TValueObject> valueObject2 ) { if ( (object)valueObject1 == null && (object)valueObject2 == null ) return true; if ( (object)valueObject1 == null || (object)valueObject2 == null ) return false; if ( valueObject1.GetType() != valueObject2.GetType() ) return false; var properties = valueObject1.GetType().GetProperties(); return properties.All( property => property.GetValue( valueObject1 ) == property.GetValue( valueObject2 ) ); } #endregion
#region !=(不相等比较)
/// <summary>
/// 不相等比较 /// </summary>
public static bool operator !=( ValueObjectBase<TValueObject> valueObject1, ValueObjectBase<TValueObject> valueObject2 ) { return !( valueObject1 == valueObject2 ); } #endregion
#region GetHashCode(获取哈希)
/// <summary>
/// 获取哈希 /// </summary>
public override int GetHashCode() { var properties = GetType().GetProperties(); return properties.Select( property => property.GetValue( this ) ) .Where( value => value != null ) .Aggregate( 0, ( current, value ) => current ^ value.GetHashCode() ); } #endregion
#region Clone(克隆副本)
/// <summary>
/// 克隆副本 /// </summary>
public virtual TValueObject Clone() { return (TValueObject)MemberwiseClone(); } #endregion } }
.Net应用程序框架交流QQ群: 386092459,欢迎有兴趣的朋友加入讨论。
谢谢你们的持续关注,个人博客地址:http://www.cnblogs.com/xiadao521/
下载地址:http://files.cnblogs.com/xiadao521/Util.2014.11.27.1.rar