代理对象来模拟即将创建的数据库
本文关键字:创建 数据库 对象 模拟 代理 | 更新日期: 2023-09-27 18:06:49
假设我有一个包含"widgets"的数据库。例如,小部件具有像长度和宽度这样的属性。最初用于创建小部件的低级API很混乱,因此我编写了一组高级函数,以使调用者更容易完成任务。数据库很奇怪,而且我不能很好地控制创建小部件对象的时间。具体来说,在处理的后期阶段,在某些其他事情首先发生之后,才能创建它。但是我希望我的调用者认为在较早的阶段已经创建了一个小部件对象,以便他们可以从一开始就获取/设置其属性。
所以,我实现了一个"ProxyWidget"对象,我的调用者可以玩。它有私有字段,如private_Length和private_Width,可以存储所需的值。然后,它还有公共属性Length和Width,我的调用者可以访问。如果调用者告诉我设置Width属性的值,逻辑是:
- 如果数据库中已经存在相应的小部件对象,则设置它的Width属性
- 如果没有,将给定的宽度值存储在private_Width字段中以供以后使用。
在稍后的某个阶段,当我确定小部件对象已经在数据库中创建时,我复制所有值:从private_Width复制到数据库Width字段,等等(不幸的是,一次一个字段/属性)。
这对于一种类型的小部件可以正常工作。但是我有大约50个类型,每个类型有大约20个不同的字段/属性,这导致了不可维护的混乱。我在想有没有更聪明的方法。也许我可以使用反射来创建"代理"对象,并以通用的方式复制字段/属性数据,而不是编写大量重复的代码?以某种方式提出公共代码?我能从"数据绑定"模式中学到什么吗?我是一名数学家,而不是程序员,我有一种不安的感觉,我目前的方法简直是愚蠢的。我的代码是c#。
首先,根据我的经验,手动编写数据访问层可能感觉像是大量重复的工作(将ORM放在适当的位置,例如NHibernate或实体框架,可能在某种程度上缓解这个问题),更新遗留的数据访问层是可怕的工作,特别是当它由许多部分组成时。
你的问题有些地方不清楚,但我想还是可以给一个高层次的回答。这些是为了给你一些想法:您可以构建
ProxyWidget
作为Widget
的替代实现(或从现有的低级API调用的任何小部件类),或者您可以实现它"在顶部",或者作为"包装器",Widget
。这是适配器设计模式。public sealed class ExistingTerribleWidget { … } public sealed class ShinyWidget // this is the wrapper that sits on top of the above { public ShinyWidget(ExistingTerribleWidget underlying) { … } private ExistingTerribleWidget underlying; … // perform all real work by delegating to `underlying` as appropriate }
我建议(至少在仍然有代码使用现有的低级API时)您使用此模式而不是创建完全独立的
Widget
实现,因为如果有数据库模式更改,您将不得不更新两个不同的API。如果您将新的EasyWidget
类构建为现有API之上的包装器,则它可以保持不变,只需更新底层实现。你描述
如果您有一个公共基类型和两个子类:一个用于尚未持久化的新部件,另一个用于已经持久化的部件,那么也许可以简化您的设计。后一个子类型可能有一个额外的数据库ProxyWidget
有两个功能(1)允许修改一个已经持久的小部件;(2)为新小部件提供缓冲区,该小部件稍后将被添加到数据库中。ID
属性,以便可以在数据库中识别、加载、修改和更新现有的小部件:interface IWidget { /* define all the properties required for a widget */ } interface IWidgetTemplate : IWidget { IPersistedWidget Create(); bool TryLoadFrom(IWidgetRepository repository, out IPersistedWidget matching); } interface IPersistedWidget : IWidget { Guid Id { get; } void SaveChanges(); }
如果您需要为许多类编写类似的代码(例如,您的50多个数据库对象类型),您可以考虑使用T4文本模板。这只会减少编写代码的重复性;但是你仍然需要在某个地方定义你的50多个对象