2

我的问题更多的是架构性质,较少涉及实际实现。

我已经构建了一个基于 WCF 的 API,但无法真正决定如何将 PL 与 BL 分开。我已经使我的服务变薄了,因此它只包含最少的实现,例如:

public TagItemResponse TagItem(TagItemRequest request)
{
   return (new ItemTagRequestProcessor()).GetResponse(request);
}

当然,第一个问题出现了,RequestProcessors 属于哪一层?我认为称它们为门面是错误的,但同时,它们与演示无关。至于现在,我决定他们仍然属于 PL。处理器方法将我的 DTO(DataContracts)作为输入,验证请求消息(基类),验证(基类)并最终返回单个 DTO 响应,如下所示:

protected override void Process(TagItemRequest request, TagItemResponse response, Host host)
{
    var profile = ProfileFacade.GetProfile(host, request.Profile);
    var item = ItemFacade.GetItemId(host, request.Item);
    var tags = new List<Tag>();

    foreach (var name in request.Tags)
    {
        var tag = TagFacade.GetTag(profile, name);
        ItemFacade.TagItem(item, tag);
        tags.Add(tag);
    }

    ItemFacade.UntagItem(item, tags);
}

现在我问自己,为什么我需要 1:1 与我的业务对象相关的外观类。例如,我有一个 HostFacade,它充当 hostDAO 和处理器之间的层。然而,它包含的逻辑很少,它只处理 DAO 调用。

public static Host GetHost(HostDTO dto)
{
   return HostDAO.GetHostByCredentials(dto.Username, dto.Password);
}

问题:我还不如合并处理器和外观,对吗?

我已经阅读了许多关于该主题的文章/书籍,但我仍然无法确定“正确”的方式,并且每次遇到问题时都倾向于选择不同的方法。我想知道是否存在正确的方法。

我找到了 f.ex。doFactory 示例,他们直接从服务实现中与 DAO 类进行对话。我不太喜欢这样,因为大多数 ServiceContract 方法共享一些逻辑,因此很适合与共享基类一起使用。

我还发现了其他示例,其中仅从服务中调用外观,但这似乎仅适用于非常细粒度的消息。我的消息是“胖”和复合的,以尽可能减少对服务的调用次数。我的额外处理层似乎是我真正的问题。

关于如何正确分层 WCF 服务可能没有单一的答案,但希望你们中的一些人的意见可以符合我的直觉,或者为我在这个主题上提供一些新的见解。

谢谢!

杰弗里

4

1 回答 1

3

首先,我假设您所说的 PL 是指表示层,而不是持久层?

在实现分层应用程序设计时,主要问题应该始终是:我能否在不影响上层实现的情况下替换较低层的实现。

持久层通常最好地说明这一点。例如,如果您从 SQL Server 2008 切换到 MySQL,持久层会发生变化(当然)。但是业务层的变化也有必要吗?例如,业务层是否捕获了仅由 SqlClient 抛出的 SqlException 实例?在一个好的设计中,业务层根本不需要改变。

同样的原则也适用于业务层和表示层的分离。

在您的示例中,我会说ItemTagRequestProcessor不应该在表示层中。首先,它与表示无关,其次,处理请求的实现与表示层无关。将其与 Web 应用程序相比,向TagItemResponse客户端呈现一个是 Web(呈现)层的关注点。检索一个实例TagItemResponse是表示层之下的一个层的关注点。

决定是否在业务层和持久层之间有一个门面是很困难的。我通常不实现外观,因为它增加了一个额外的(通常是不必要的)间接层。此外,我认为直接从业务层方法调用持久层方法没有问题。只要你考虑到同样的原则:你能不能改变持久层的实现而不影响业务层的实现。

亲切的问候,

罗纳德·维尔登伯格

于 2009-03-19T15:00:06.523 回答