长期运行,有状态的'服务'适合DDD?

时间:2014-03-06 07:58:10

标签: c# design-patterns domain-driven-design cqrs onion-architecture

在更多行业或自动化相关的应用程序(主要依赖于他们必须管理的外部组件)中,您经常会遇到这样的情况:域包含的模型不仅仅是真实问题的抽象,但也是在域外实际存在的东西的表示和指针。

例如,使用代表网络设备的此域实体:

public class NetworkDevice {
   public IPAddress IpAddress { get; set; }
}

应用程序可能需要根据域内的表示来管理外部组件,而不仅仅是存储或验证此类实体或对实体更改采取措施。现在,DDD甚至适合这种情况吗?那些经理域名服务?

埃里克·埃文斯在其着名的蓝皮书中描述,域名服务需要是一个无状态模型,实现从 ubiquitos language 中获取的方法,以满足对该实体的请求,或者存储库本身无法处理。但是,如果服务需要有状态,该怎么办?

一个简单示例:应用程序需要监视网络已配置的 IP设备,以便通知域内其他应用程序有关状态事件的信息。如果IP设备在应用程序内部注册(例如存储在数据库中),则会通知“ping-service”并开始监视设备。

public class PingMonitor : IDisposable,
   IHandle<DeviceRegisteredEvent>,
   IHandle<DeviceRemovedEvent> 
{

    public List<NetworkDevice> _devices = new List<NetworkDevice>();

    public void Handle(DeviceRegisteredEvent @event) {
        _devices.Add(@event.Device);
    }

    public void Handle(DeviceRemovedEvent @event) {
        _devices.Remove(@event.Device);
    }

    public void PingWorker() {
        foreach(var device in _devices) {
            var status = Ping(device.IpAddress);
            if(status != statusBefore)
                DomainEvents.Raise<DeviceStateEvent>(new DeviceStateEvent(device, status));
        }
    }

}

然后,其他组件可以处理这些状态事件,例如如果设备离线,请停止通过其他协议与设备通话。

现在,那些组件是什么?起初我认为它们是域服务,因为它们满足域的某些要求。但是,它们有状态以及不具体代表 ubiquitos language ping-service 的任务是 ping 域实体和报告它的状态,但 ping-service 未实现客户端允许ping设备的方法。

他们是应用服务吗?这些组件在DDD模式中的适用范围是什么?

2 个答案:

答案 0 :(得分:2)

在DDD中,长时间运行的过程称为 Saga 。它通常使用域事件实现。

以下是该主题的一些介绍: http://abdullin.com/journal/2010/9/26/theory-of-cqrs-command-handlers-sagas-ars-and-event-subscrip.html/

答案 1 :(得分:1)

我曾经实现了类似的功能,希望它有所帮助:)

我们的组织拥有在线支付处理应用程序。一旦客户完成付款,在线支付提供商就会发送指示成功或失败的通知。发生网络故障时,通知可能永远不会到达我们的应用程序。因此,这里有不满的客户。因此需要一种自动检查机制。

应用程序运行器负责保持检查运行:

public class CheckingBatch {
    private TransactionChecker transactionChecker;

    public void run() {
        List<Transaction> transactions = transactionsToBeChecked();
        for (Transaction transaction : transactions) {
                //publish events if the transaction needs check
                doCheck(transaction, now);                }
        } 
    }

    private List<Transaction> transactionsToBeChecked() {
         return transactionRepository.findBy(transactionChecker
            .aToBeCheckedSpec());
    }
}

Annother应用程序服务侦听事件并进行实际检查:

public class CheckTransactionServiceImpl implements CheckTransactionService {
    private TransactionChecker transactionChecker;

    @Transactional
    public void check(final TransactionNo transactionNo) {
        Transaction transaction = transactionRepository.find(transactionNo);
        CheckResult result = transactionChecker.check(transaction);
        //handle check result
    }
}

TransactionCheck是一种在线支付解决方案不可知的域名服务:

public interface TransactionChecker {
/**
 * 
 * | data between online-payment provider and ours | txn STATUS | RESULT |<br>
 * | consistent | CLOSED | VALID |<br>
 * | inconsistent | CLOSED | INVALID |<br>
 * others omitted
 */
    CheckResult check(Transaction transaction);
/**
 * returns txn specification to filter to be checked ones.
 */
    ToBeCheckedSpecification aToBeCheckedSpec();
}

正如您所看到的,应用程序服务和域服务现在都是无状态的。

恕我直言,Ping是域服务(与TxnChecker相关),但监视器是一种应用程序服务(与CheckingBatch相关)。