2010-04-27 7 views
2

VB 2008 .NET 3.5Можно ли ограничить экземпляр объекта только одним другим (родительским) объектом в VB.NET?

Предположим, у нас есть два класса: Order и OrderItem, которые представляют собой некоторую систему онлайн-заказа. OrderItem представляет одну позицию в заказе. Один заказ может содержать несколько OrderItems в виде списка (OrderItem).

Public Class Order 
    Public Property MyOrderItems() as List(of OrderItem) 
    End Property 
End Class 

Имеет смысл, что OrderItem не должен существовать без Ордера. Другими словами, класс OrderItem не может быть создан сам по себе, он должен зависеть от класса Order, чтобы его содержать и создавать. Однако OrderItem должен быть общедоступным в области видимости, чтобы свойства были доступны другим объектам. Таким образом, требования к OrderItem:

  1. Может быть создан только классом Order.

  2. Должно быть общедоступным, чтобы любой другой объект мог получить доступ к его свойствам/методам через объект Order. например Order.OrderItem (0) .ProductID.

  3. OrderItem должен быть передан другим субподряду/функциям, которые будут работать на нем.

Как достичь этих целей? Есть ли лучший подход?

ответ

3

Стандартный способ сделать это - разоблачить OrderItem как интерфейс, а затем реализовать его в частном классе внутри класса Order. Класс OrderItem может быть создан только внутри класса Order, но он может быть открыт снаружи через общий интерфейс IOrderItem. Нравится так:

Public Interface IOrderItem 
    ReadOnly Property ItemCode() As Integer 
    ReadOnly Property NumberOfItems() As Integer 
    ReadOnly Property Description() As String 
End Interface 

Public Class Order 

    Private m_Items As List(Of IOrderItem) 

    Public ReadOnly Property Items() As List(Of IOrderItem) 
     Get 
      Return m_Items 
     End Get 
    End Property 

    Private Class OrderItem 
     Implements IOrderItem 

     Private m_Code As Integer 
     Private m_NumItems As Integer 
     Private m_Description As String 

     Public Sub New(ByVal code As Integer, ByVal numItems As Integer, ByVal desc As String) 
      m_Code = code 
      m_NumItems = numItems 
      m_Description = desc 
     End Sub 

     Public ReadOnly Property Description() As String Implements IOrderItem.Description 
      Get 
       Return m_Description 
      End Get 
     End Property 

     Public ReadOnly Property ItemCode() As Integer Implements IOrderItem.ItemCode 
      Get 
       Return m_Code 
      End Get 
     End Property 

     Public ReadOnly Property NumberOfItems() As Integer Implements IOrderItem.NumberOfItems 
      Get 
       Return m_NumItems 
      End Get 
     End Property 
    End Class 
End Class 
+0

Речь идет о самом изящном решении, которое я видел. Мне жаль, что для этого не существует какой-либо языковой конструкции, так как я много работаю с ее совокупными/составными классами. –

+0

Не могли бы такие объявления разрешить любой сборке реализовывать 'IOrderItem', но он считает нужным, и передавать такие реализации на ничего не подозревающий код, который ожидает, что он будет реализован так, как это делает' 'OrderItem''? – supercat

4

Вы можете сделать один конструктор OrderItem, который принимает Order вещь.

В этом конструкторе вы можете добавить OrderItem в коллекцию Order.MyOrderItems.

Это удовлетворит ваши требования.

Public Class OrderItem 
    Public Sub New(ByRef myOrder As Order) 
     myOrder.MyOrderItems.Add(Me) 
    End Sub 
End Class 
  1. Вы можете создать экземпляр OrderItem только путем передачи действительного Order объекта к нему.
  2. Публикация и может быть вызвана по мере необходимости (Order.OrderItem(0).ProductID).
  3. OrderItem может быть передан другим подписчикам и функциям.
+0

Это очень близко, и это решение, с которым я столкнулся. Однако я не сформулировал свои первые критерии правильно, поэтому я пересмотрел его. Единственная проблема с этим методом заключается в том, что он требует только того, чтобы Ордер существовал где-то, а не того, что заказ выполняет экземпляр. Извините за смешение. –

+0

@Casey - Вы хотите, чтобы класс был общедоступным, но может быть создан только конкретным другим классом. Насколько я знаю, это невозможно в .NET (или большинстве других языков OO). – Oded

+0

Единственный способ использования метода @Stephen Martin - использовать рефлексию для проверки стека вызовов, который будет по-настоящему дорогостоящим вызовом каждый раз, и я не думаю, что кто-нибудь его порекомендовал. Очевидно, что он будет работать только во время выполнения. Но я брошу его сюда, черт возьми. Если новый System.Diagnostics.StackTrace(). GetFrame (1) .GetMethod(). Name <> "CreateAndAddOrder" Затем выкидывает новое приложениеException («Invalid Caller») –

2

OrderItem «s конструктор должен быть friend (только подъезд Order) - я говорю, потому что с помощью friendfriend вы можете ограничить видимость из OrderItem» s конструктора для классов в той же сборке. Примечание: это решение подразумевает, что Order and OrderItem находятся в одной библиотеке/сборке, и вы пытаетесь использовать их с другой сборки - в противном случае защита friend не работает.

responsablity для создания OrderItem объектов должны принадлежать только Order:

Построить метод, как на Order класса: Public Function CreateOrderItem(whateverParametersYouNeed) as OrderItem, что внутренне создает новый OrderItem, добавляет его в OrderItem список и возвращает ссылку на вновь созданный пункт.

Теперь вы можете делать все, что хотите, с этим OrderItem - он всегда будет принадлежать списку Order.

+0

Что вы подразумеваете под модулем? У меня создалось впечатление, что модификатор Friend сделает его видимым для всего в сборке. –

+0

сборкой было слово, которое я должен был использовать не модулем. – Ando

 Смежные вопросы

  • Нет связанных вопросов^_^