有趣的API设计/模式

时间:2009-02-04 18:47:25

标签: c# vb.net design-patterns orm api-design

我正在重新设计内部ORM工具的一部分,我想直接向最终开发人员公开Field(一个代表数据库中字段的类,如CustomerFirstName)。

所以这很容易实现,但是API有点难看,因为这个Field类以前在内部使用过于开放。例如,这只是一个小例子:IsDirty属性不是只读的,这是最终开发人员不应该篡改的东西。

我想过可能会创建两个接口,IPublicField和IPrivateField,并尝试让字段类实现它们。但是,继续使用IsDirty示例,我不想要这样的东西:

Public ReadOnly Property PrivateIsDirty Implements IPrivateField.IsDirty
 ...
End  Property

Public Property IsDirty Implements IPublicField.IsDirty
 ...
End  Property

...这只是有点难看,加上你仍然可以回到Field类并进入非readonly方法。我也不想引入一个单独的setter方法,因为它是我不想考虑的另一个重大变化,它也会与API的其他部分产生不一致。

我最终将Field类重命名为InnerField,并在其周围创建了一个facade / wrapper样式结构,如下所示:

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类提供了最终开发人员所需的简化锁定工具。

所以,假设这是连贯的,我想知道你如何在这种情况下继续前进,以及我的解决方案是否从外部看起来是合理的。

谢谢!

4 个答案:

答案 0 :(得分:2)

在isDirty属性的特定情况下,您可以只限制setter的范围:

public bool IsDirty
     {
        get
        {
            // logic here that the end-devs can use safely.
        }
        private set
        {
            // logic here that is only exposed to other members of your private
            // ORM assembly.
        }
    }

答案 1 :(得分:2)

在VB.NET的上下文中,您可以给出IsDirty属性范围的setter。如果你希望这个属性由程序集中的其他类“set-able”,那么只需将它作为朋友:

Public Property IsDirty() As Boolean
    Get
        Return _isDirty
    End Get
    Friend Set(ByVal trueFalse As Boolean)
        _isDirty = trueFalse
    End Set
End  Property

现在,任何外部程序集都可以检查IsDirty属性,但只有同一程序集中的类才能设置它。

答案 2 :(得分:1)

你可以尝试使用CAS。这是一个例子:

    public bool IsDirty
    {
        get;
        [StrongNameIdentityPermissionAttribute(SecurityAction.LinkDemand, Name = "<assembly name>")]
        set;
    }

该属性位于System.Security。

如果您担心开发人员可能会通过反射调用它,您可能希望将LinkDemand更改为Demand:但您也可以'替换'那些开发人员而不是SecurityAction:)。

唯一的问题是,现在您已在运行时进行检查。这可能不是你想要的,但如果没有重大的重组努力,我无法看到它以任何其他方式运作。

答案 3 :(得分:1)

如果您不反对使用get和set方法而不是属性,请尝试使用IPublicField实现IPrivateField。

Public Interface IPrivateField
    Function GetDirty() As Boolean
End Interface

Public Interface IPublicField
    Inherits IPrivateField

    Sub SetDirty(ByVal dirty As Boolean)
End Interface

Public Class Whatever
    Implements IPublicField

    Public Function GetDirty() As Boolean Implements IPrivateField.GetDirty
        ' logic here
    End Function

    Public Sub SetDirty(ByVal dirty As Boolean) Implements IPublicField.SetIsDirty
        ' logic here
    End Sub
End Class

或者,如果您可以放弃VB并切换到C#,这可以正常工作:

public interface IPrivateField
{
    bool IsDirty { get;}
}

public interface IPublicField : IPrivateField
{
    new bool IsDirty { get; set; }
}

public class Whatever : IPublicField
{
    public bool IsDirty 
    {
        get
        {
            // logic here
        }
        set
        {
            // logic here
        }
    }
}