Интересный API дизайн / паттерн - PullRequest
0 голосов
/ 04 февраля 2009

Я перепроектирую часть нашего внутреннего инструмента 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 и войти в метод non-readonly. Я также не хотел вводить отдельный метод установки, потому что это было бы еще одно критическое изменение, о котором я не хочу думать, и это также привело бы к несоответствию с другими частями 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 предоставляет упрощенный, закрытый инструмент, который нужен конечным разработчикам.

Итак, предполагая, что это было логично, мне было интересно, как вы могли поступить в этой ситуации и кажется ли мое решение разумным со стороны.

Спасибо!

Ответы [ 4 ]

2 голосов
/ 05 февраля 2009

В контексте VB.NET вы можете задать установщик области свойств IsDirty. Если вы хотите, чтобы это свойство было доступным для установки другими классами в сборке, просто задайте для него значение как Friend:

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

Теперь любая внешняя сборка может проверить свойство IsDirty, но только классы в одной сборке могут установить его.

2 голосов
/ 04 февраля 2009

В конкретном случае свойства isDirty вы можете просто ограничить область действия установщиков:

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 голос
/ 04 февраля 2009

Если вы не возражаете против использования метода 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
        }
    }
}
1 голос
/ 04 февраля 2009

Вы можете попробовать , используя CAS в своих интересах. Вот пример:

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

Атрибут находится в System.Security.

Возможно, вы захотите изменить LinkDemand на Demand, если вы обеспокоены тем, что ваши разработчики могут вызвать его через рефлексию, но вы также можете «заменить» этих разработчиков вместо SecurityAction :).

Единственный улов в том, что теперь у вас есть проверки во время выполнения. Это, вероятно, не то, что вы хотите, но я не вижу, чтобы это работало как-то иначе без серьезных усилий по реструктуризации.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...