c# - “Do not use Abstract Base class in Design; but in Modeling/Analysis”

标签 c# .net wcf soa ooad

虽然我在 OOAD 方面有一些经验,但我是 SOA 的新手。

SOA 设计的准则之一是“仅将抽象类用于建模。从设计中省略它们”。抽象的使用有助于建模(分析阶段)。

在分析阶段,我想出了一个 BankAccount 基类。从它派生的专门类是“FixedAccount”和“SavingsAccount”。我需要创建一个服务来返回用户的所有帐户(帐户列表)。满足要求的服务结构应该是什么?

注意:如果您能提供使用WCF 的代码演示,那就太好了。

最佳答案

听起来您正在尝试使用 SOA 远程访问您的对象模型。您最好查看希望服务公开的交互和功能,并避免公开服务实现的继承细节。

所以在这种情况下,您需要一个用户帐户列表,您的界面看起来应该是这样的

[ServiceContract]
interface ISomeService
{
    [OperationContract]
    Collection<AccountSummary> ListAccountsForUser(
        User user /*This information could be out of band in a claim*/);
}

[DataContract]
class AccountSummary
{
     [DataMember]
     public string AccountNumber {get;set;}
     [DataMember]
     public string AccountType {get;set;}
     //Other account summary information
}

如果您决定走继承路线,您可以使用 KnownType attribute ,但请注意,这会将一些类型信息添加到通过线路发送的消息中,这在某些情况下可能会限制您的互操作性。

更新:

我之前回答时时间有限,所以我会尝试详细说明为什么我喜欢这种风格。

我不建议通过 DTO 在单独的层中公开您的 OOAD,这通常会导致界面臃肿,您在其中传递大量未使用的数据,并虔诚地将其映射到本质上是您的域模型删除了所有逻辑,我只是​​看不到它的值(value)。我通常围绕它公开的操作设计我的服务层,并且我使用 DTO 来定义服务交互。

使用基于公开操作而非域模型的 DTO 有助于保持服务封装并减少与域模型的耦合。通过不公开我的域模型,我不必为了序列化而在字段可见性或继承方面做出任何妥协。

例如,如果我将一个 Transfer 方法从一个帐户公开到另一个帐户,服务接口(interface)将如下所示:

[ServiceContract]
interface ISomeService
{
    [OperationContract]
    TransferResult Transfer(TransferRequest request);
}

[DataContract]
class TransferRequest
{
     [DataMember]
     public string FromAccountNumber {get;set;}
     [DataMember]
     public string ToAccountNumber {get;set;}
     [DataMember]
     public Money Amount {get;set;}
}

class SomeService : ISomeService
{
    TransferResult Transfer(TransferRequest request)
    {
        //Check parameters...omitted for clarity
        var from = repository.Load<Account>(request.FromAccountNumber);
        //Assert that the caller is authorised to request transfer on this account
        var to = repository.Load<Account>(request.ToAccountNumber);
        from.Transfer(to, request.Amount);
        //Build an appropriate response (or fault)
    }
}

现在从这个界面上,消费者可以很清楚调用这个操作所需的数据是什么。如果我将其实现为

[ServiceContract]
interface ISomeService
{
    [OperationContract]
    TransferResult Transfer(AccountDto from, AccountDto to, MoneyDto dto);
}

而AccountDto是account中字段的副本,作为消费者,我应该填充哪些字段?他们全部?如果添加新属性以支持新操作,则所有操作的所有用户现在都可以看到此属性。 WCF 允许我将此属性标记为非强制性属性,这样我就不会破坏我的所有其他客户端,但如果它对新操作是强制性的,则客户端只有在调用该操作时才会发现。

更糟糕的是,作为服务实现者,如果他们向我提供了当前余额会怎样?我应该相信它吗?

这里的一般规则是询问谁拥有数据,客户还是服务?如果客户端拥有它,那么它可以将它传递给服务,在进行一些基本检查后,服务可以使用它。如果服务拥有它,客户端应该只传递足够的信息让服务检索它需要的信息。这允许服务保持其拥有的数据的一致性。

在这个例子中,服务拥有账户信息,定位它的键是一个账号。虽然该服务可能会验证金额(正数、支持的货币等),但这是由客户拥有的,因此我们希望 DTO 上的所有字段都被填充。

总而言之,我已经看到它以所有 3 种方式完成,但围绕特定操作设计 DTO 是迄今为止最成功的服务和​​消费者实现方式。它允许操作独立发展,并且非常明确地说明服务期望什么以及将返回给客户端的什么。

关于c# - “Do not use Abstract Base class in Design; but in Modeling/Analysis”,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9470013/

相关文章:

c# - 缺少将 Microsoft.IdentityModel.Clients.ActiveDirectory 3.13.9 与 Azure KeyVault C# SDK 结合使用的程序集引用

C# ModInverse 函数

c# - bulkCopy.WriteToServer 不复制

c# - 数组或迭代器 - 对于返回一个/两个元素的调用具有更好的性能特征(内存方面)

WCF : FaultContract(typeof(ExceptionDetail)) issue

c# - 可滚动图片框c#.net使用双缓冲停止闪烁

c# - WCF 用户名身份验证 : Can I get the Username in a custom ServiceAuthorizationManager?

.net - 部署 .NET WinForms 应用程序的最恶劣的企业环境是什么?

c# - 为 SOAP 网络服务传递 WSSE Usernametoken 的正确方式

c# - 自宿主 WCF ServiceHost 对象生存期