我开始研究DDD,在“深入研究”之前,我想了解一些概念。有人能帮助澄清一些概念吗?
假设我们有一个用于身份验证的聚合,让我们将其命名为AuthenticationAggregate,,在这个聚合中,我有一个聚合根,比方说Authentication.cs.在这个根目录中,我想处理身份验证,但是凭据可以以多种形式出现,例如电子邮件/密码(AuthenticationCredentials1)组合体、姓氏/道布(AuthenticationCredentials2),等等。
例如,IAuthenticationRepository的实现将如何工作?应该在聚合根上创建IAuthenticationCredentials实体的属性吗?如果是,如何处理不同身份验证凭据的不同属性?
谢谢你提前提供帮助。
-为了清楚起见-编辑
Authentication.cs
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
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....
}
}发布于 2019-05-04 13:34:45
让我们用不同的凭据来解决这个问题。有一种方法可以做到这一点:继承。您的代码必须检查不同类型的凭据,并在必要时转换为具体类型。如果要在转换之前进行一些检查,还可以添加凭据类型代码。下面是一个例子。
public enum CredentialsType { type1, type2 }
public interface IAuthenticationCredentials {
CredentialsType Type { get; }
}现在是关于坚持。这取决于你使用的数据库。如果是关系数据库管理系统(例如MySQL),您可以使用单表继承、混凝土表继承、类表继承。
如果它是面向文档的,如MongoDB,则可以将它们存储为具有不同属性和类型属性的文档,以便在进行查询或将它们映射到类时区分它们。或者你可以使用不同的集合。
ORMs确实提供了实现继承映射的不同方式。您必须根据您使用的具体ORM搜索特定的解决方案。例如,搜索如何在Dapper中进行单表继承。
编辑:在类型铸造:
我是富域模型的拥护者,我确实认为对象应该有行为,而不仅仅是被视为数据。类型转换最好避免,因为您可以向类添加行为并避免它。
尽管如此,有时弹出的只是数据。让我们以Events为例。事件只是数据,仅此而已。其他对象需要获取并处理这些数据。下面是一个示例(我将避免存储,只是在内存中简化事情):
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
}
}在上面的例子中,我们可以注意到一些事情。
EventHistory时,需要使用IEvent类型定义Queue,以便存储多个不同类型的缩进对象。我们的Dequeue方法将需要返回IEvent。EventProcessor将使用从事件类型到eventHandler的映射。此地图需要声明为Dictionary<Type, Action<IEvent>>。为了将委托存储到方法,需要定义方法void handler(IEvent)。因为我们需要处理具体的事件,我们需要铸造。另一种选择是使用dynamic,但这将导致我们搜索属性而不是类型转换。这避免了强制转换,但是,在强类型语言中搜索未知对象类型的属性是一个完整的单独讨论。这里的重要观察是,对象的每个AccountAddedEvent)类型(例如,EventProcessor)表示一个包含特定于的属性的Things),是另一个对象(EventProcessor)将需要的)。处理器不仅对属性感兴趣,还需要知道事件的类型才能处理它。
在这种情况下,类型铸造是可以的。如果我们使用的是一种松散的类型化语言(如JavaScript ),我们只需向对象添加一个属性eventType并打开它。然后,我们可以得到每个属性,没有类型铸造。
在您的示例中,没有关于如何使用这些类的特定场景的信息,因此我假设代码中的另一个对象将需要登录的数据和类型,以便它能够解释它们。证书本身不会有太多的行为。如果我弄错了,您需要给出一个详细的示例和场景,这些示例和场景将告诉我们如何使用它们。
另一种方法是使用一个仅重新呈现一袋数据的对象。就像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次?在强类型语言中搜索属性并不是一件容易的事。它可能会混淆您的代码,您将失去强大的输入的好处。
https://stackoverflow.com/questions/55976910
复制相似问题