gpt4 book ai didi

oop - 如何设计通用业务实体并且仍然是面向对象的?

转载 作者:行者123 更新时间:2023-12-03 13:31:59 25 4
gpt4 key购买 nike

我正在开发一种包装产品,该产品应(在一定程度上)满足各种需求(在一定程度上)的多个客户,因此应以足够灵活的方式构建,以便可以由每个特定客户定制。我们在这里讨论的定制类型是,对于某些关键业务对象,不同的客户可能具有不同的属性。而且,它们可能还具有与其附加属性相关的不同业务逻辑。

作为一个非常简单的示例:将“汽车”视为系统中的业务实体,因此具有4个关键属性,即VehicleNumber,YearOfManufacture,Price和Colour。

使用该系统的客户端之一可能会向汽车增加2个属性,即ChassisNumber和EngineCapacity。此客户端需要与这些字段关联的一些业务逻辑,以在添加新的Automobile时验证系统中不存在相同的机箱编号。

另一个客户端只需要一个称为SaleDate的附加属性。 SaleDate拥有自己的业务逻辑检查,可在输入销售日期时验证该车辆是否在某些警察记录中不作为被盗车辆存在。

我的大部分经验主要是为单个客户端制作企业应用程序,我真的很努力地了解如何处理属性是动态的并且还具有在面向对象范式中具有动态业务逻辑的能力的业务实体。

关键的问题


是否有任何通用的面向对象的原则/模式可以帮助我应对这种设计?


我确信从事通用/包装产品工作的人们在大多数情况下都会面临类似的情况。任何建议/指针/一般指导也表示赞赏。

我的技术是.NET 3.5 / C#,该项目具有分层的体系结构,其中的业务层由包含其业务逻辑的业务实体组成

最佳答案

这是我们最大的挑战之一,因为我们有多个客户端都使用相同的代码库,但是需求却千差万别。让我与您分享我们的进化故事:

我们的公司最初只有一个客户,随着我们开始吸引其他客户,您将开始在代码中看到如下内容:

if(clientName == "ABC") {
// do it the way ABC client likes
} else {
// do it the way most clients like.
}


最终,我们明智地发现了这样的事实,即这使得代码非常丑陋且难以管理。如果另一个客户希望他们的行为在一个地方像ABC一样,而CBA在另一个地方则像我们一样,我们就会陷入困境。因此,我们改为使用带有一系列配置点的.properties文件。

if((bool)configProps.get("LastNameFirst")) {
// output the last name first
} else {
// output the first name first
}


这是一个改进,但仍然很笨拙。 “魔术弦”比比皆是。各个属性之间没有真正的组织或文档。许多属性依赖于其他属性,如果未正确组合,则不会做任何事情(甚至会破坏某些内容!)。在某些迭代过程中,我们的大部分时间(可能甚至大部分时间)都花在了修复错误上,因为我们已经为一个客户端“修复”了某些问题,从而破坏了另一个客户端的配置。当我们有了一个新的客户端时,我们将从另一个客户端的属性文件开始,该客户端的配置“最像”该客户端想要的配置,然后尝试进行调整,直到它们看起来正确为止。

我们尝试使用各种技术使这些配置点不太笨拙,但仅取得了适度的进展:

if(userDisplayConfigBean.showLastNameFirst())) {
// output the last name first
} else {
// output the first name first
}


有一些项目可以控制这些配置。其中一个涉及编写基于XML的视图引擎,以便我们可以更好地为每个客户端自定义显示。

<client name="ABC">
<field name="last_name" />
<field name="first_name" />
</client>


另一个项目涉及编写配置管理系统以合并我们的配置代码,强制每个配置点都记录在案,允许超级用户在运行时更改配置值,并允许代码验证每个更改以避免无效组合配置值。

这些不同的变化无疑使每个新客户的生活变得轻松很多,但是其中大多数未能解决我们问题的根源。真正使我们受益最多的更改是,当我们停止将产品视为一系列修复程序以使更多客户能够使用某些产品时,便开始将我们的产品视为“产品”。当客户要求新功能时,我们开始认真考虑以下问题:


现在或将来有多少其他客户端可以使用此功能?
可以通过不降低我们代码的可管理性的方式来实现它吗?
我们是否可以实现他们所要求的其他功能,而该功能仍可以满足他们的需求,同时更适合其他客户重用?


实施功能时,我们将放眼长远。我们可能会创建一个全新的表,该表可以允许任何客户端定义任意数量的自定义字段,而不是创建仅由一个客户端使用的新数据库字段。这将需要更多的前期工作,但是我们可以允许每个客户以极大的灵活性定制他们自己的产品,而无需程序员更改任何代码。

就是说,有时有些某些定制如果不对复杂的Rule引擎等投入大量精力就无法真正完成。当您只需要使一个客户端使用一种方式而另一客户端使用另一种方式时,我发现您最好的选择是对接口进行编程并利用依赖注入。如果您遵循“ SOLID”原则,以确保代码以良好的“关注点分离”等模块化方式编写,那么为特定客户端更改代码的特定部分的实现几乎不会痛苦:

public FirstLastNameGenerator : INameDisplayGenerator
{
IPersonRepository _personRepository;
public FirstLastNameGenerator(IPersonRepository personRepository)
{
_personRepository = personRepository;
}
public string GenerateDisplayNameForPerson(int personId)
{
Person person = _personRepository.GetById(personId);
return person.FirstName + " " + person.LastName;
}
}

public AbcModule : NinjectModule
{
public override void Load()
{
Rebind<INameDisplayGenerator>().To<FirstLastNameGenerator>();
}
}


我前面提到的其他技术增强了这种方法。例如,我没有编写 AbcNameGenerator,因为也许其他客户端在他们的程序中会想要类似的行为。但是,使用这种方法,您可以非常灵活和可扩展地轻松定义模块,以覆盖特定客户端的默认设置。

因为这样的系统本质上是脆弱的,所以将重点放在自动化测试上也很重要:单个类的单元测试,确保(例如)注入绑定都正常工作的集成测试以及确保所有内容正常运行的系统测试一起工作而不会退缩。

PS:即使我在公司的大部分历史中并未真正在公司工作,我也会在整个故事中使用“我们”。

PPS:原谅C#和Java的混合。

关于oop - 如何设计通用业务实体并且仍然是面向对象的?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/4838845/

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