工厂或服务模式或方法注入?

时间:2010-02-19 14:09:04

标签: c# java .net design-patterns

我目前正考虑采用何种模式解决以下问题。

我有一个名为IdentificationRequest的实体。该实体用于通过某些标准识别Person

public class IdentificationRequest
{
     public IdentificationCriteria Criteria;
     public Person IdentifiedPerson;

     protected internal virtual void RedirectToManualIdentification()
     {
        ChangeState(IdentificationRequestState.ManualIdentificationRequested);
     }

     public virtual void StartManualIdentification()
     {
        ChangeState(IdentificationRequestState.ManualIdentificationInProgress);
     }

     public virtual void AssignIdentifiedPerson(Person person)
     {
        identifiedPerson = person;
        ChangeState(IdentificationRequestState.IdentificationFinished);       
     }
}

public class IdentificationCriteria
{
     public string Name;
}

这是一个简化的例子。实际上,IdentificationRequest包含更多信息,以及IdentificationCriteria

基本上,客户端使用IdentificationRequest创建IdentificationCriteria,然后需要识别正确的Person。为此,需要将标准传递给持久层,以检查数据库中是否有符合条件的人员。如果找不到人,则需要进行人工干预,以便为请求分配正确的Person

对于识别过程,我目前正在使用服务。像:

    public class IdentificationService : IIdentificationService
        {
            private readonly IPersonRepository personRepository ;
            private readonly IIdentificationRequestRepository identificationRequestRepository;

            public IdentificationService(IPersonRepository personRepository )
            {
                this.personRepository = personRepository ;
            }

            public bool IdentifyPerson(IdentificationRequest identificationRequest)
            {
                var matches = personRepository.FindByIdentificationCriteria(identificationRequest.Criteria);

                // some additional post analysis of the matches returned from the persistence layer
                var criteriaAnalyzer = new IdentificationCriteriaAnalyzer(identificationRequest.Criteria);
                var uniqueMatch = criteriaAnalyzer.TryIdentify(matches);

                if(uniqueMatch != null)
                {
                    identificationRequest.AssignIdentifiedPerson(uniqueMatch);
                    return true;
                }
                else
                {
                    identificationRequest.RedirectToManualIdentification();
                    return false;
                }            
            }
        }

此服务是域程序集的一部分。现在我的问题是,如果这是执行识别的正确模式?或者我会使用工厂来创建识别请求,然后直接尝试识别它,例如:

public class IdentificationRequestFactory
{
    private readonly IPersonRepository personRepository;

    public IdentificationRequestFactory(IPersonRepository personRepository)
    {
        this.personRepository = personRepository;
    }

    public IdentificationRequest Create(IdentificationCriteria identificationCriteria)
    {
        var request = new IdentificationRequest(identificationCriteria);

        var matches = personRepository.FindByIdentificationCriteria(identificationRequest.Criteria);
        var criteriaAnalyzer = new IdentificationCriteriaAnalyzer(identificationRequest.Criteria);
        var uniqueMatch = criteriaAnalyzer.TryIdentify(matches);

        if(uniqueMatch != null)
        {
            identificationRequest.AssignIdentifiedPerson(uniqueMatch);

        }
        else
        {
            identificationRequest.RedirectToManualIdentification();

        }

        return request;
    }
}

这样,IdentificationRequest只能由工厂构建,确保已经完成识别过程并且请求处于有效状态。

或者你会让IdentificationRequest通过像下面这样的方法注入来识别自己:

public class IdentificationRequest
{
    public IdentificationCriteria Criteria;
    public Person IdentifiedPerson;

    public void Identify(IPersonRepository personRepository)
    {
        // identification logic here
    }
}

此示例将识别过程直接耦合到请求。

这种情况的常见模式是什么?反正有共同的模式吗?有什么优点和缺点?

提前谢谢!

更新

也许我没有正确理解命令模式,但在这种情况下我能得到什么好处?以下实现是否正确?

public class IdentificationCommandFactory
{
    private readonly IPersonRepository personRepository;

    public IdentificationCommandFactory(IPersonRepository personRepository)
    {

        this.personRepository = personRepository;
    }

    public IIdentificationCommand Create(IdentificationRequest identificationRequest)
    {
        var matches = personRepository.FindByIdentificationCriteria(identificationRequest);
        var criteriaAnalyzer = new IdentificationCriteriaAnalyzer(identificationRequest);
        var uniqueMatch = criteriaAnalyzer.TryIdentify(matches);

        if(uniqueMatch != null)
        {                
            return new AssignIdentifiedPersonCommand(identificationRequest, uniqueMatch);
        }
        else
        {                
            return new RedirectToManualIdentificationCommand(identificationRequest);
        }    
    }

}

public interface IIdentificationCommand
{
    void Execute();
}

public class RedirectToManualIdentificationCommand : IIdentificationCommand
{
    private readonly IdentificationRequest identificationRequest;

    public RedirectToManualIdentificationCommand(IdentificationRequest identificationRequest)
    {
        this.identificationRequest = identificationRequest;
    }

    public void Execute()
    {
        identificationRequest.RedirectToManualIdentification();
    }
}

public class AssignIdentifiedPersonCommand : IIdentificationCommand
{
    private readonly IdentificationRequest identificationRequest;
    private readonly Person personIdentified;

    public AssignIdentifiedPersonCommand(IdentificationRequest identificationRequest, Person personIdentified)
    {
        this.identificationRequest = identificationRequest;
        this.personIdentified = personIdentified;
    }

    public void Execute()
    {
        identificationRequest.AssignIdentifiedPerson(personIdentified);
    }
 }

来电者:

    var identificationCommandFactory = new IdentificationCommandFactory(personRepository);

    var command = identificationCommandFactory.Create(request);

    command.Execute();

3 个答案:

答案 0 :(得分:5)

开发的主要目标应该是使用最简单,最干净的代码来满足要求。 (http://msdn.microsoft.com/en-us/magazine/cc163962.aspx

话虽如此,除非您有特定理由使用其中一种模式,否则请立即停止。如果没有具体的理由去做这项工作,你只需编写更多的代码,希望它有一天会有用。只要写出有效的方法。如果需要,稍后重构它。

如果需要,继续沿着保持简单的道路前进。选择一个模式,库或其他工具,使您可以编写干净,简单,可读的代码来完成工作。

答案 1 :(得分:0)

您的IdentificationCriteria和IdentificationCriteriaAnalyzer类型在我看来很像Specifications,所以我会看看在这个方向重构它们是否有意义。

在我看来,IdentificationRequest类打破了Single Responsibility Principle - 为什么它有一个Person字段/属性?

API也可以从更好的Command-Query Separation中受益。

所以我认为更好的模型是定义一个接受IdentificationCriteria并返回某种Command的接口。这样的界面基本上是抽象工厂

public interface IIdentificationCommandFactory
{
    IIdentificationCommand Create(IdentificationCriteria spec);
}

当您实现它时,您可以在您的repostiry中查找匹配项,并根据该查询的结果和您的其他规范(例如IdentificationCriteriaAnalyzer),您可以返回正确的IIdentificationCommand实现。

然后调用者会要求返回的命令执行。

答案 2 :(得分:0)

在我看来,你应该使用命令模式:
- http://www.dofactory.com/Patterns/PatternCommand.aspx
- http://c2.com/cgi/wiki?CommandPattern
- http://en.wikipedia.org/wiki/Command_pattern

此外,您的IdentificationRequest不像entity class,但我会将您的Person类描述为实体。
通常命令模式中的Invoker向接收者发送响应,指示成功或失败,并且在成功的情况下,响应对象可以包含已识别的角色。