我知道这匹马已经逃跑了(至少现在是这样),但是避免使用不同的模式会为您节省一个痛苦的世界。下一个最好的方法是为 80% 的解决方案提供一个通用架构,并仔细管理如何处理可变部分。
就您的实际问题而言,孤立地...听起来 依赖注入 在这种情况下可能是您的朋友。
一般架构看起来像这样。发生了一些不同的事情,让我依次解释一下。
- 每个客户端都有自己的数据库和相应的数据访问代码;数据访问代码的每个实例都实现相同的接口:
IClientDataProvider。
- 数据访问代码以北的所有代码都针对
IClientDataProvider 进行编程。我假设您有单独的业务逻辑和 UI 层 - 但这与您的问题无关。
- DI(依赖注入)子系统在运行时决定加载哪个实际的数据访问代码(因此也决定加载哪个数据库)。
这里的假设是,无论架构如何,这些差异都可以由数据访问代码处理,并使用一个一致的接口。
接口和数据提供者设计 - 该图描述了最基本的解决方案,但它很容易扩展。例如,假设您有两个不同的概念:
- 客户资料数据(姓名、地址、喜欢的颜色等)。
- 客户端传输网络数据(不同客户端)。
制作两种不同类型的接口,一种用于通用数据(配置文件数据),另一种用于处理不同数据(传输网络数据)。常见的只需要你开发一个实现,所以你只需要在必要的地方为接口编写重复的代码。
专业提示 - 如果您还没有听说过,一定要熟悉Interface Segregation Principle (ISP),以便在您开始设计界面时使用。
您可能会问,如果只有一种实现常见的东西,您是否需要使用接口?您不需要,您可以直接使用对象 - 但是:
- 全面使用接口意味着架构和代码更加一致,更易于长期维护。
- 从长远来看,就地接口使解决方案更容易更改。例如。假设您想更改数据提供者技术?或者客户的需求要求您在以前相同的领域有所不同。
DTOs - 要获取周围的数据,创建一套完全愚蠢的对象来保存信息;系统使用这些来移动数据。例如:
PizzaInfo info = IClientDataProvider.GetClientPizzaData(guid clientId)
IClientDataProvider.Save(KittenInfo kitten);
最简单的解决方案是制作一组所有层都使用的那些。如果您愿意,您显然可以选择对其进行更改。
在运行时选择哪个数据提供者 - 我猜这取决于用户访问租户的方式。例如。有一些东西(可能在 DI 子系统中)通过 URL 传递,并调用加载哪个提供程序。
hogwarts.holdencms.com = CMS.DataAccess.Clients.HogwartsDataProvider
starwars.holdencms.com = CMS.DataAccess.Clients.StarWarsDataProvider
thunderbirds.holdencms.com = CMS.DataAccess.Clients.ThunderBirdsDataProvider
如果客户端之间的差异不能包含在一组接口中怎么办?这个答案分为两个部分:在高层次上重用相同的方法/原则,但将其用于加载不同的业务逻辑类和/或不同的 UI 小部件。第二部分,这不是我亲身体验过的领域,但我很确定大多数体面的 UI 框架都会有一些东西来帮助你做这类事情。