有趣的 API 设计/模式
我正在重新设计我们内部 ORM 工具的一部分,并且我想直接向最终开发人员公开 Field(表示数据库中字段的类,如 CustomerFirstName)。
所以这很容易完成,但是 API 有点难看,因为这个 Field 类以前在内部使用并且太开放了。 例如,这只是一个小例子:IsDirty 属性不是只读的,这是最终开发人员不应该能够篡改的。
我考虑过创建两个接口,IPublicField 和 IPivateField,并尝试让字段类来实现这两个接口。 然而,继续 IsDirty 示例,我不想要这样的东西:
Public ReadOnly Property PrivateIsDirty Implements IPrivateField.IsDirty
...
End Property
Public Property IsDirty Implements IPublicField.IsDirty
...
End Property
...这有点难看,而且您仍然可以转换回 Field 类并进入非只读方法。 我也不想引入单独的 setter 方法,因为这将是我不想考虑的另一个重大更改,而且它还会造成与 API 其他部分的不一致。
我最终将 Field 类重命名为 InnerField,并围绕它创建了一个外观/包装样式结构,如下所示:
Public Class Field
Implements BusinessObjects.IField
Private InnerField As BusinessObjects.IInnerField
Public Sub New(ByVal field As IInnerField)
InnerField = field
End Sub
...
Public ReadOnly Property IsDirty() As Boolean Implements BusinessObjects.IField.IsDirty
Get
Return InnerField.IsDirty
End Get
End Property
...
End Class
这似乎效果很好。 在内部,InnerField 是适当开放的,我们可以在未来自由地使其更加开放,而不会影响最终开发人员,而在外部,Field 类提供了最终开发人员需要的简化的锁定工具。
因此,假设这是一致的,我想知道在这种情况下你会如何进行,以及我的解决方案从外部看来是否合理。
谢谢!
I am re-designing part of our internal ORM tool, and I want to expose Field (a class that represents a field in the database, like CustomerFirstName) directly to the end-developer.
So that was easy enough to accomplish, however the API got a little ugly because this Field class was previously used internally and is too open. For instance, and this is just one small example: the IsDirty property was not read-only, and that's something end-developers shouldn't be able to tamper with.
I thought about maybe creating two interfaces, IPublicField and IPrivateField, and trying to get the field class to implement both of them. However, continuing with the IsDirty example, I didn't want something like this:
Public ReadOnly Property PrivateIsDirty Implements IPrivateField.IsDirty
...
End Property
Public Property IsDirty Implements IPublicField.IsDirty
...
End Property
...It's just a little ugly, plus you could still cast back to the Field class and get into the non-readonly method. I also didn't want to introduce a seperate setter method because it would be another breaking change that I don't want to think about, and it also would create an inconsistency with other parts of the API.
I ended up renaming the Field class to InnerField, and creating a facade/wrapper style structure around it like this:
Public Class Field
Implements BusinessObjects.IField
Private InnerField As BusinessObjects.IInnerField
Public Sub New(ByVal field As IInnerField)
InnerField = field
End Sub
...
Public ReadOnly Property IsDirty() As Boolean Implements BusinessObjects.IField.IsDirty
Get
Return InnerField.IsDirty
End Get
End Property
...
End Class
This seems to be working out pretty well. Internally, the InnerField is suitably open and we have the freedom to make it more open in the future without impacting end-developers, and externally the Field class provides the simplified, locked down tool that end-developers need.
So, assuming that was coherent, I was wondering how you might have proceeded in this situation, and whether my solution seems reasonable from the outside.
Thanks!
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
在 isDirty 属性的特定情况下,您可以限制设置器的范围:
In the specific case of the isDirty property, you could just restrict the scope of the setters:
在 VB.NET 上下文中,您可以指定 IsDirty 属性范围的设置器。 如果您希望程序集中的其他类可以“设置”此属性,只需将其范围设置为 Friend:
现在,任何外部程序集都可以检查 IsDirty 属性,但只有同一程序集中的类可以设置它。
In the context of VB.NET, you can give the setter of the IsDirty property scope. If you want this property "set-able" by other classes in the assembly, just make it scoped as Friend:
Now, any outside assembly can check the IsDirty property, but only classes within the same assembly can set it.
您可以尝试使用 CAS 对您有利。 下面是一个示例:
该属性位于 System.Security 中。
如果您担心开发人员可能通过反射调用它,您可能需要将 LinkDemand 更改为 Demand:但您也可以“替换”这些开发人员而不是 SecurityAction :)。
唯一的问题是现在您可以在运行时进行检查。 这可能不是您想要的,但如果不进行重大重组工作,我看不出它会以任何其他方式发挥作用。
You could try using CAS to your advantage. Here is an example:
The attribute is in System.Security.
You might want to change LinkDemand to Demand if you are worried that your developers might call it through reflection: but you could also 'replace' those developers instead of the SecurityAction :).
The only catch is that now you have the checks at runtime. This probably isn't what you want, but I can't see it working any other way without major restructuring efforts.
如果您不反对使用 get 和 set 方法而不是属性,请尝试让 IPublicField 实现 IPrivateField。
或者,如果您可以放弃 VB 并切换到 C#,这也可以正常工作:
If you don't object to using a get and set method instead of a property, trying having IPublicField implement IPrivateField.
Alternately, if you can ditch VB and switch to C#, this works just fine: