gpt4 book ai didi

language-agnostic - 数据存储组织

转载 作者:行者123 更新时间:2023-12-04 07:42:39 26 4
gpt4 key购买 nike

因此,我正在开发一些软件,并努力让自己使用 TDD 和其他最佳实践。

我正在尝试编写测试来定义类和存储库。

假设我有类 CustomerOrderOrderLine

现在,我是否将 Order 类创建为类似的东西

abstract class Entity {
int ID { get; set; }
}

class Order : Entity {
Customer Customer { get; set; }
List<OrderLine> OrderLines { get; set; }
}

这将很好地序列化,但是,如果我不关心 OrderLinesCustomer 详细信息就不会像人们希望的那样轻量级。或者我只是将 ID 存储到项目中并添加一个获取它们的函数?

class Order : Entity {
int CustomerID { get; set; }
List<OrderLine> GetOrderLines() {};
}

class OrderLine : Entity {
int OrderID { get; set; }
}

你会如何为这样的东西构建存储库?

我是否使用带有方法的抽象 CRUD 存储库 GetByID(int), Save(entity), Delete(entity) 每个项目repository 继承自,并添加了它自己的特定方法,像这样?

public abstract class RepositoryBase<T, TID> : IRepository<T, TID> where T : AEntity<TID>
{
private static List<T> Entities { get; set; }

public RepositoryBase()
{
Entities = new List<T>();
}

public T GetByID(TID id)
{
return Entities.Where(x => x.Id.Equals(id)).SingleOrDefault();
}

public T Save(T entity)
{
Entities.RemoveAll(x => x.Id.Equals(entity.Id));
Entities.Add(entity);
return entity;
}

public T Delete(T entity)
{
Entities.RemoveAll(x => x.Id.Equals(entity.Id));
return entity;
}
}

这里的“最佳实践”是什么?

最佳答案

实体

让我们从 Order 实体开始。订单是一个自主对象,不依赖于“父”对象。在领域驱动设计中,这称为聚合根;它是整个订单聚合的根。订单聚合由根实体和几个子实体组成,在本例中为 OrderLine 实体。

聚合根负责管理整个聚合,包括子实体的生命周期。不允许其他组件访问子实体;对聚合的所有更改都必须通过根。此外,如果根不复存在,子级也不复存在,即没有父订单就不能存在订单行。

Customer 也是一个聚合根。它不是订单的一部分,它只与订单相关。如果订单不复存在,则客户不复存在。反之,如果客户不复存在,您将希望保留顺序以用于簿记目的。因为 Customer 只是相关的,所以您希望订单中只有 CustomerId

class Order
{
int OrderId { get; }

int CustomerId { get; set; }

IEnumerable<OrderLine> OrderLines { get; private set; }
}

存储库

OrderRepository 负责根据需要加载整个 Order 聚合或其中的一部分。它不负责加载客户。如果您需要客户,请使用订单中的 CustomerIdCustomerRepository 加载它。

class OrderRepository
{
Order GetById(int orderId)
{
// implementation details
}

Order GetById(int orderId, OrderLoadOptions loadOptions)
{
// implementation details
}
}

enum OrderLoadOptions
{
All,
ExcludeOrderLines,
// other options
}

如果您之后需要加载订单行,您应该使用告诉,不要询问 原则。告诉订单加载其订单行,以及要使用的存储库。然后订单会告诉存储库它需要知道的信息。

class Order
{
int OrderId { get; }

int CustomerId { get; set; }

IEnumerable<OrderLine> OrderLines { get; private set; }

void LoadOrderLines(IOrderRepository orderRepository)
{
// simplified implementation
this.OrderLines = orderRepository.GetOrderLines(this.OrderId);
}
}

请注意,代码使用 IOrderRepository 来检索订单行,而不是使用单独的订单行存储库。领域驱动设计指出每个聚合根都应该有一个存储库。检索子实体的方法属于根的存储库,只能由根访问。

抽象/基础存储库

我自己写过带有CRUD操作的抽象仓库,但是我发现它并没有增加任何值(value)。当您想在代码中传递子类的实例时,抽象很有用。但是什么样的代码会接受任何 BaseRepository 实现作为参数?

此外,每个实体的 CRUD 操作可能不同,这使得基础实现变得无用。您真的要删除订单,还是只是将其状态设置为已删除?如果删除客户,相关订单会怎样?

我的建议是保持简单。远离抽象和通用基类。当然,所有存储库都共享某种功能,而且泛型看起来很酷。但你真的需要它吗?

关于language-agnostic - 数据存储组织,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/3868056/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com