首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >DDD -域模型与实体继承

DDD -域模型与实体继承
EN

Stack Overflow用户
提问于 2019-05-03 20:47:20
回答 1查看 1.6K关注 0票数 2

我开始研究DDD,在“深入研究”之前,我想了解一些概念。有人能帮助澄清一些概念吗?

假设我们有一个用于身份验证的聚合,让我们将其命名为AuthenticationAggregate,,在这个聚合中,我有一个聚合根,比方说Authentication.cs.在这个根目录中,我想处理身份验证,但是凭据可以以多种形式出现,例如电子邮件/密码(AuthenticationCredentials1)组合体、姓氏/道布(AuthenticationCredentials2),等等。

例如,IAuthenticationRepository的实现将如何工作?应该在聚合根上创建IAuthenticationCredentials实体的属性吗?如果是,如何处理不同身份验证凭据的不同属性?

谢谢你提前提供帮助。

-为了清楚起见-编辑

Authentication.cs

代码语言:javascript
复制
public class Authentication : IAggregateRoot
{
    //uncertain of this
    private IAuthenticationCredentials _authenticationCredentials;
    public IAuthenticationCredentials AuthenticationCredentials => _authenticationCredentials;

    protected Authentication()
    {
    }

    public void Authenticate(string email, string password)
    {
        _authenticationCredentials = new AuthenticationCredentials1(email, password);
    }

    public void Authenticate(string name, DateTime dob)
    {
        _authenticationCredentials = new AuthenticationCredentials2(name, dob);
    }
}

AuthenticationRepository.cs

代码语言:javascript
复制
public class AuthenticationRepository : IRepository<Authentication>
{
    private readonly IDatabase _db;

    public AuthenticationRepository(IDatabase db)
    {
        _db = db ?? throw new ArgumentNullException("db");    
    }

    public async Task<Authentication> Authenticate(Authentication authenticationAggregateRoot)
    {
        //persistence logic here
        //say if I use a micro-orm like dapper, how do I populate the where clause based on
        authenticationAggregateRoot.AuthenticationCredentials....
    }
}
EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2019-05-04 13:34:45

让我们用不同的凭据来解决这个问题。有一种方法可以做到这一点:继承。您的代码必须检查不同类型的凭据,并在必要时转换为具体类型。如果要在转换之前进行一些检查,还可以添加凭据类型代码。下面是一个例子。

代码语言:javascript
复制
public enum CredentialsType { type1, type2 }


public interface IAuthenticationCredentials {
    CredentialsType Type { get; }
}

现在是关于坚持。这取决于你使用的数据库。如果是关系数据库管理系统(例如MySQL),您可以使用单表继承混凝土表继承类表继承

这里有一篇关于继承映射的文章

如果它是面向文档的,如MongoDB,则可以将它们存储为具有不同属性和类型属性的文档,以便在进行查询或将它们映射到类时区分它们。或者你可以使用不同的集合。

ORMs确实提供了实现继承映射的不同方式。您必须根据您使用的具体ORM搜索特定的解决方案。例如,搜索如何在Dapper中进行单表继承。

编辑:在类型铸造:

我是富域模型的拥护者,我确实认为对象应该有行为,而不仅仅是被视为数据。类型转换最好避免,因为您可以向类添加行为并避免它。

尽管如此,有时弹出的只是数据。让我们以Events为例。事件只是数据,仅此而已。其他对象需要获取并处理这些数据。下面是一个示例(我将避免存储,只是在内存中简化事情):

代码语言:javascript
复制
public interface IEvent { // empty, just a marker interface }

public class AccountRegisteredEvent : IEvent {
    public Guid AccountGuid { get; private set; }
    public Email AccountEmail { get; private set; }
    public string UserName { get; private set; } 
}

public class CommentAdded : IEvent {
    public GuidAccountGuid { get; private set; }
    public string Comment { get; private set; }
}

public class EventHistory {

    private readonly Queue<IEvent> mEvents;

    public void Enqueue(IEvent event) { ..... }

    public IEvent Dequeue() {
        return mEvents.Dequeue();
    }
}

public class EventProcessor {
    private Dictionary<Type, Action<IEvent> mEventTypeHanlerMap;

    public EventProcessor() {
        mEventTypeHandlerMap = new Dictionary<Type, Action<IEvent>();

        meventTypeHandlerMap.Add(
            typeof(AccountAddedEvent),
            ProcessAccountAdded);
        // add other event handlers
    }

    public void Process(IEvent event) {
        var handler = mEventTypeHanlerMap[event.GetType()];
        handler(event);
    }

    private void ProcessAccountAdded(IEvent event) {
        var accountAddedEvent = (AccountAddedEvent)event;
        // process
    }

    private void ProcessCommentAdded(IEvent event) {
        var commentAdded = (CommentAddedEvent)event;
        // process
    }
}

在上面的例子中,我们可以注意到一些事情。

  • 由于在本例中我们使用的是强类型语言C#,所以在执行EventHistory时,需要使用IEvent类型定义Queue,以便存储多个不同类型的缩进对象。我们的Dequeue方法将需要返回IEvent。
  • 我们的EventProcessor将使用从事件类型到eventHandler的映射。此地图需要声明为Dictionary<Type, Action<IEvent>>。为了将委托存储到方法,需要定义方法void handler(IEvent)。因为我们需要处理具体的事件,我们需要铸造。另一种选择是使用dynamic,但这将导致我们搜索属性而不是类型转换。这避免了强制转换,但是,在强类型语言中搜索未知对象类型的属性是一个完整的单独讨论。

这里的重要观察是,对象的每个AccountAddedEvent)类型(例如,EventProcessor)表示一个包含特定于的属性的Things),是另一个对象(EventProcessor)将需要的)。处理器不仅对属性感兴趣,还需要知道事件的类型才能处理它。

在这种情况下,类型铸造是可以的。如果我们使用的是一种松散的类型化语言(如JavaScript ),我们只需向对象添加一个属性eventType并打开它。然后,我们可以得到每个属性,没有类型铸造。

在您的示例中,没有关于如何使用这些类的特定场景的信息,因此我假设代码中的另一个对象将需要登录的数据和类型,以便它能够解释它们。证书本身不会有太多的行为。如果我弄错了,您需要给出一个详细的示例和场景,这些示例和场景将告诉我们如何使用它们。

另一种方法是使用一个仅重新呈现一袋数据的对象。就像JavaScript中的对象一样,您只需将一个属性粘贴到它上,它要么在那里,要么不存在。

代码语言:javascript
复制
public class AuthenticationCredentials {

    private Dictionary<string, string> mData;

    public bool HasProperty(string propertyName) {}
    public void SetValue(string propertyName, string value) {}
    public string GetValue(string propertyName) {}
}

如果您不需要(UserNameAndPassword、EmailAndCode、PhoneAndCode)之类的类型,您的处理代码将只搜索属性。如果需要类型,可以将其作为属性添加并检查它。

就个人而言,如果您需要知道特定类型的凭据,我会选择类型转换。我不认为你会有那么多类型的登录。最多3到5次?在强类型语言中搜索属性并不是一件容易的事。它可能会混淆您的代码,您将失去强大的输入的好处。

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/55976910

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档