规格模式(Specification)

需求如下:需要从数据库的Cargo表中取出商品名称为“钉子”的货物。
可以这样做:
public class CargoRepository
{
public List SelectByPartName(string partName){}
}
当需求发生变化了,它要从数据库的Cargo表中取出商品编码为“0001”的货物。
可以这样做:
public class CargoRepository
{
public List SelectByPartCode(string partCode){}
}
当需求又一次变化了,它要从数据库的Cargo表中取出商品名称为“钉子”并且商品编码为“0001”的货物。
这时候问题严重了,看下上面的方法都是一些特定的查询,可能还有很多这样的查询。
他们单个的查询通过组合又形成了新的查询。这就是组合爆炸。
有两种模式可以解决这样的问题:Specification-[Evans的DDD]和Query Object[Fowler,PEAA],这里只讨论Specification。
在DDD一书中提到:
(原文如下:业务规则不适于放在任何已有实体或值对象中,而且规则的变化和组合会掩盖那些领域对象的基本含义。)
有时经常造成组合爆炸。规格是模型的一部分,将它们从实体或值对象中独立出来有助于使模型更加清晰,它表达的是业务的规则。规格是值对象,它用来判断对象是否满足标准的谓词。谓词是指计算结果为true或false的函数,可以用and、or、not操作符连接。
对规格的接口定义:
规格模式(Specification)public interface ISpecification
规格模式(Specification)规格模式(Specification)    规格模式(Specification){
规格模式(Specification)        bool isSatisfiedBy(object candidate);
规格模式(Specification)
规格模式(Specification)        ISpecification and(ISpecification other);
规格模式(Specification)        ISpecification or(ISpecification other);
规格模式(Specification)        ISpecification not();
规格模式(Specification)    }
我们希望具体的规格只实现isSatisfiedBy方法,所以定义抽象类:
public abstract class AbstractSpecification : ISpecification
{
#region ISpecification 成员
public abstract bool isSatisfiedBy(object candidate);
public ISpecification and(ISpecification other)
{
AndSpecification andSpec = Singleton<AndSpecification>.Instance();
andSpec.SetAndSpecification(this, other);
return andSpec;
}
public ISpecification or(ISpecification other)
{
OrSpecification orSpec = Singleton<OrSpecification>.Instance();
orSpec.SetOrSpecification(this, other);
return orSpec;
}
public ISpecification not()
{
NotSpecification notSpec = Singleton<NotSpecification>.Instance();
notSpec.SetNotSpecification(this);
return notSpec;
}
#endregion
}
定义操作符谓词:
规格模式(Specification)internal class AndSpecification : AbstractSpecification
    规格模式(Specification){
规格模式(Specification)        ISpecification one;
规格模式(Specification)        ISpecification other;
规格模式(Specification)        public void SetAndSpecification(ISpecification x, ISpecification y)
规格模式(Specification)规格模式(Specification)        规格模式(Specification){
规格模式(Specification)            one = x;
规格模式(Specification)            other = y;
规格模式(Specification)        }
规格模式(Specification)        public override bool isSatisfiedBy(object candidate)
        规格模式(Specification){
规格模式(Specification)            return one.isSatisfiedBy(candidate) && other.isSatisfiedBy(candidate);
规格模式(Specification)        }
规格模式(Specification)    }
规格模式(Specification)internal class OrSpecification : AbstractSpecification
    规格模式(Specification){
规格模式(Specification)        ISpecification one;
规格模式(Specification)        ISpecification other;
规格模式(Specification)        public void SetOrSpecification(ISpecification x, ISpecification y)
        规格模式(Specification){
规格模式(Specification)            one = x;
规格模式(Specification)            other = y;
规格模式(Specification)        }
规格模式(Specification)        public override bool isSatisfiedBy(object candidate)
        规格模式(Specification){
规格模式(Specification)            return one.isSatisfiedBy(candidate) || other.isSatisfiedBy(candidate);
规格模式(Specification)        }
规格模式(Specification)    }
规格模式(Specification)internal class NotSpecification : AbstractSpecification
    规格模式(Specification){
规格模式(Specification)        ISpecification wrapped;
规格模式(Specification)        public void SetNotSpecification(ISpecification notSpec)
        规格模式(Specification){
规格模式(Specification)            wrapped = notSpec;
规格模式(Specification)        }
规格模式(Specification)        public override bool isSatisfiedBy(object candidate)
        规格模式(Specification){
规格模式(Specification)            return !wrapped.isSatisfiedBy(candidate);
规格模式(Specification)        }
规格模式(Specification)    }
如果使用规格模式,系统中会存在许多小颗粒的规格类。性能会有影响。这里使用享元模式获取规格。
规格模式(Specification)public class SpecificationFactory
    规格模式(Specification){
规格模式(Specification)        private static readonly SpecificationFactory instance = new SpecificationFactory();
规格模式(Specification)        private Dictionary<string, ISpecification> m_SpecList;
规格模式(Specification)
        private SpecificationFactory() 规格模式(Specification){ }
规格模式(Specification)
规格模式(Specification)        public static SpecificationFactory Instance()
        规格模式(Specification){
规格模式(Specification)            return instance;
规格模式(Specification)        }
规格模式(Specification)
规格模式(Specification)        public ISpecification GetSepcification(string assembly,string type)
        规格模式(Specification){
规格模式(Specification)            ISpecification spec;
            if (m_SpecList==null) 规格模式(Specification){ m_SpecList = new Dictionary<string, ISpecification>(); }
规格模式(Specification)            string key = assembly + type;
规格模式(Specification)            if (!m_SpecList.ContainsKey(key))
            规格模式(Specification){
规格模式(Specification)                spec = Assembly.Load(assembly).CreateInstance(type) as ISpecification;
                if (spec!=null) 规格模式(Specification){ m_SpecList.Add(key, spec); return spec; }
规格模式(Specification)                throw new Exception(type + "规格不存在,请确保存" + assembly + "中存在" + type + "类");
规格模式(Specification)            }
规格模式(Specification)            return m_SpecList[key];
规格模式(Specification)        }
规格模式(Specification)    }
这里简单的测试:
规格模式(Specification)[TestMethod]
规格模式(Specification)        public void TestSpec()
        规格模式(Specification){
规格模式(Specification)            SpecificationFactory sf = SpecificationFactory.Instance();
规格模式(Specification)            Cargo cargo=null;
规格模式(Specification)            ISpecification spec = sf.GetSepcification("Bmrxntfj", "Bmrxntfj.Specification.NullSpecification");
规格模式(Specification)            Assert.AreEqual(true, spec.isSatisfiedBy(cargo));
规格模式(Specification)            spec=spec.or(new EqualSpecification());
规格模式(Specification)            Assert.AreEqual(true, spec.isSatisfiedBy(cargo));
规格模式(Specification)            cargo = new Cargo();
规格模式(Specification)            cargo.PartCode = 2;
规格模式(Specification)            cargo.PartName = "2";
规格模式(Specification)            Assert.AreEqual(false, spec.isSatisfiedBy(cargo));
规格模式(Specification)        }
然而我们却不常这样做。因为有些ORM框架采用对象的属性来查询。在基础结构层中生成SQL,这样我们就不需要这样麻烦了。
标签: DDD Specification    
相关文章:
领域驱动开发推荐代码示例 — Microsoft NLayerApp
总结一下领域模型的验证(附代码下载)
什么是领域驱动设计(Domain Driven Design)?
在ASP.NET MVC3中使用EFCodeFirst 1.0
Tags: 

延伸阅读

最新评论

发表评论