惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

博客园_首页
爱范儿
爱范儿
罗磊的独立博客
V
V2EX
量子位
Last Week in AI
Last Week in AI
Hugging Face - Blog
Hugging Face - Blog
博客园 - 司徒正美
Jina AI
Jina AI
博客园 - 叶小钗
小众软件
小众软件
博客园 - 【当耐特】
Y
Y Combinator Blog
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
T
Tailwind CSS Blog
博客园 - 聂微东
Microsoft Security Blog
Microsoft Security Blog
美团技术团队
P
Proofpoint News Feed
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
有赞技术团队
有赞技术团队
MongoDB | Blog
MongoDB | Blog
Recent Announcements
Recent Announcements
酷 壳 – CoolShell
酷 壳 – CoolShell

博客园 - bmrxntfj

通过match看rust 聊一聊Rust的enum 折旧记录某旅纵横app分析研究 实现自己的js框架 实现自己的Linq to Sql 统一的仓储接口 ddd官方终于发布了一个完整的示例 浅谈值对象 分层随想 prototype模式随想 ddd心得 ddd分层感想 小boss随想 论软件的价值 Composite模式随想 DDD书籍介绍 Bmrxntfj.UIMapper界面对象映射 闲来没事,写个老玩意 Strategy与Template Method
规格模式(Specification)
bmrxntfj · 2008-02-17 · via 博客园 - bmrxntfj

规格模式(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操作符连接。

对规格的接口定义:

public interface ISpecification
    
{
        
bool isSatisfiedBy(object candidate);

        ISpecification and(ISpecification other);
        ISpecification or(ISpecification other);
        ISpecification not();
    }

我们希望具体的规格只实现isSatisfiedBy方法,所以定义抽象类:

public abstract class AbstractSpecification : ISpecification
    
{
        
ISpecification 成员

定义操作符谓词:

internal class AndSpecification : AbstractSpecification
    
{
        ISpecification one;
        ISpecification other;
        
public void SetAndSpecification(ISpecification x, ISpecification y)
        
{
            one 
= x;
            other 
= y;
        }

        
public override bool isSatisfiedBy(object candidate)
        
{
            
return one.isSatisfiedBy(candidate) && other.isSatisfiedBy(candidate);
        }

    }

internal class OrSpecification : AbstractSpecification
    
{
        ISpecification one;
        ISpecification other;
        
public void SetOrSpecification(ISpecification x, ISpecification y)
        
{
            one 
= x;
            other 
= y;
        }

        
public override bool isSatisfiedBy(object candidate)
        
{
            
return one.isSatisfiedBy(candidate) || other.isSatisfiedBy(candidate);
        }

    }

internal class NotSpecification : AbstractSpecification
    
{
        ISpecification wrapped;
        
public void SetNotSpecification(ISpecification notSpec)
        
{
            wrapped 
= notSpec;
        }

        
public override bool isSatisfiedBy(object candidate)
        
{
            
return !wrapped.isSatisfiedBy(candidate);
        }

    }

如果使用规格模式,系统中会存在许多小颗粒的规格类。性能会有影响。这里使用享元模式获取规格。

public class SpecificationFactory
    
{
        
private static readonly SpecificationFactory instance = new SpecificationFactory();
        
private Dictionary<string, ISpecification> m_SpecList;

        
private SpecificationFactory() { }

        
public static SpecificationFactory Instance()
        
{
            
return instance;
        }


        
public ISpecification GetSepcification(string assembly,string type)
        
{
            ISpecification spec;
            
if (m_SpecList==null{ m_SpecList = new Dictionary<string, ISpecification>(); }
            
string key = assembly + type;
            
if (!m_SpecList.ContainsKey(key))
            
{
                spec 
= Assembly.Load(assembly).CreateInstance(type) as ISpecification;
                
if (spec!=null{ m_SpecList.Add(key, spec); return spec; }
                
throw new Exception(type + "规格不存在,请确保存" + assembly + "中存在" + type + "");
            }

            
return m_SpecList[key];
        }

    }

这里简单的测试:

[TestMethod]
        
public void TestSpec()
        
{
            SpecificationFactory sf 
= SpecificationFactory.Instance();
            Cargo cargo
=null;
            ISpecification spec 
= sf.GetSepcification("Bmrxntfj""Bmrxntfj.Specification.NullSpecification");
            Assert.AreEqual(
true, spec.isSatisfiedBy(cargo));
            spec
=spec.or(new EqualSpecification());
            Assert.AreEqual(
true, spec.isSatisfiedBy(cargo));
            cargo 
= new Cargo();
            cargo.PartCode 
= 2;
            cargo.PartName 
= "2";
            Assert.AreEqual(
false, spec.isSatisfiedBy(cargo));
        }

然而我们却不常这样做。因为有些ORM框架采用对象的属性来查询。在基础结构层中生成SQL,这样我们就不需要这样麻烦了。