1

我正在寻找一些关于具有一些特殊性的客户端/服务器解决方案架构的建议。

客户端是一个相当粗的客户端,将服务器主要留给持久性、并发性和基础架构问题。服务器包含许多包含敏感信息和公共信息的实体。例如,假设实体是人,假设社会安全号码和姓名是敏感的并且年龄是公开可见的。

启动客户端时,用户会看到许多实体,但不会泄露任何敏感信息。在任何时候,用户都可以选择登录并针对服务器进行身份验证,只要身份验证成功,用户就可以访问敏感信息。

客户端正在托管一个域模型,我正在考虑将其实现为某种“延迟加载”,使第一个请求实例化实体,然后用敏感数据刷新它们。实体获取器会在敏感信息未被披露时抛出异常,fe:

class PersonImpl : PersonEntity
{
    private bool undisclosed;

    public override string SocialSecurityNumber {
        get {
            if (undisclosed)
                throw new UndisclosedDataException();

            return base.SocialSecurityNumber;
        }
    }
}

另一种更友好的方法可能是有一个值对象来指示该值是未公开的。

get {
    if (undisclosed)
        return undisclosedValue;

    return base.SocialSecurityNumber;
}

一些担忧:

  • 如果用户登录然后退出,敏感数据已经加载,但必须再次披露。
  • 有人可能会争辩说,这种类型的功能属于域内,而不是某些基础设施实现(即存储库实现)。
  • 与往常一样,在处理大量属性时,这种类型的功能可能会使代码混乱

任何见解或讨论表示赞赏!

4

2 回答 2

2

我认为这实际上是使用视图模型的一个很好的例子。您的担忧似乎与实体的消费直接相关,因为它们包含数据。除了将实体一直传递到 UI 之外,您还可以将它们限制为仅存在于域内 - 即根本没有实体传入或传出域,大多数/所有活动都通过命令/查询方法完成在存储库上。然后存储库将返回视图模型而不是实体。

那么这如何/为什么适用?您实际上可以有两个不同的视图模型。一种用于经过身份验证的用户,另一种用于未经过身份验证的用户。您在经过身份验证的视图模型中公开敏感数据的实际值,而不是在未经身份验证的视图模型中公开。您可以让它们派生自一个通用接口,然后针对该接口而不是对象类型进行编码。对于未经过身份验证的用户的具体实现,您可以只填充非敏感数据,让敏感的 getter 执行您希望他们执行的操作。

我的观点有几点:

  • 我不喜欢实体中的延迟加载。延迟加载是数据访问职责,并不是模型的真正组成部分。对我来说,它是我在我的领域中强烈避免的事情的一流成员,以及分页和排序。至于如何将这些项目关联在一起,我宁愿通过 ID 指针将对象松散地耦合到其他实体。如果我想要/需要这些实体之一包含的数据,那么我可以加载它。它在某种程度上有点像延迟加载,但我通过这样做强制它永远不会在域模型本身中发生。
  • 我不喜欢在 getter 上抛出异常。另一方面,二传手很好。我是这样看的。实体应始终处于有效状态。Getter 不会影响实体的状态 - setter 会。投掷二传手是在加强模型的完整性。使用两个视图模型方法可以让我将逻辑转移给演示者。所以,我基本上可以做一些类似“如果用户是未经授权的类型,则执行此操作;否则执行其他操作”之类的操作。由于您所指的最终将是数据如何呈现给用户的情况,而不是对模型很重要,我认为它很合适。通常,我对可以为 null 的属性使用可为 null 的类型,并且不对 getter 强制执行任何操作,因为它通常不是其职责的一部分。反而,

明显的缺点是使用视图模型需要更多的编码,但它带来了将表示和视图与域解耦的明显好处。它还有助于单元/集成测试,您可以在其中验证某个视图模型不能返回某种类型的数据。

但是,您可以使用类似于AutoMapper的东西(取决于您的平台是什么)来帮助从您的实体填充您的视图模型。

于 2010-05-19T13:24:38.607 回答
0

我在没有创建 OpenId 的情况下发布问题是错误的,所以看起来我必须在这里发表评论(?)。

首先,感谢您抽出宝贵时间来回答 - 这当然更多地与数据的呈现方式有关,而不是模型的工作原理。但是,我觉得有必要澄清一些事情。域模型/实体永远不会直接从 UI 中引用。我正在使用 DM-V-VM 模式的变体来分离 UI/业务模型。对于一般的延迟加载和存储库实现,我在基础设施层中有实体实现,其中处理序列化、脏跟踪和延迟加载等事情。

所以领域层有如下实体:

class Entity {
    virtual string SocialSecurityNumber { get; }
}

基础设施层添加了一些其他功能,以便能够从服务器更新和恢复实体:

class EntityImpl : Entity {
    bool isDirty;
    bool isLoaded;
    // Provide the means to set value on deserialization
    override string SocialSecurityNumber;
}

所以延迟加载行为将在基础设施层实现,而领域层永远不会看到。

我同意使用 getter 并不好,但我担心的是匿名视图模型如何检索数据。到目前为止,要检索实体列表,视图模型将保存对域存储库的引用,如果我有两个存储库,一个用于经过身份验证(并因此公开)的实体,另一个用于未经身份验证的用户 - 甚至可能是两个不同的实体?

于 2010-05-20T12:18:31.207 回答