2013-06-24 4 views
1

, поэтому у меня есть вопрос о проверке того, был ли объект создан с использованием конкретного конструктора. У меня есть класс, называемый SearchWithTwoLevelCore, который является частью поисковой системы. Он имеет конструктор, как это:Лучший способ проверить, правильно ли был создан экземпляр экземпляра

public SearchWithTwoLevelCache(ISearchCore s, ICurrentTimeProvider tp) 
    { 
     //Initialize the two levels. 
     S=s; 
     lvl2 = TimeBoundedQueryCache(s.AsQueryDataSource, tp, TimeSpan(24,0,0)); 
     lvl1 = SizeBoundedQueryCache(lvl2, 10); 


    } 

Где S, lvl1 и LVL2 являются все частные поля объявлены в классе, которые держат объекты других общественных классов. Затем у меня есть общедоступный метод, который я хочу запустить, который находится внутри SearchWithTwoLevelClass, но сначала я хочу проверить, был ли конструктор, используемый для создания SearchWithTwoLevelCache, тем, который был выше, иначе метод не будет работать нормально и выкинет какое-то исключение, т. Каков наилучший способ сделать это? Большое спасибо заранее!

+1

Если существует несколько конструкторов, и ваш метод зависит от состояния объекта, на основе которого был вызван конструктор, вы можете захотеть переместить эти аргументы в сам вызов функции. Таким образом, у вас нет зависимостей от последовательности, и единственный способ, которым вы можете вызвать этот метод, - это данные, которые ему необходимы для успеха. – dash

+0

«Лучший способ проверить, был ли экземпляр экземпляром надлежащим образом», вероятно, «не *» проверяет, был ли конструктор, используемый для того, чтобы SearchWithTwoLevelCache был выше ». – haim770

ответ

4

Это хороший пример важности Liskov Substitution Principle. Я очень люблю изображение, используемое в this answer.

Если ваш класс имеет несколько конструкторов, и успех вашего метода зависит от того, какой конструктор был вызван, тогда у вас есть несколько вариантов.

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

1) реорганизовать объекты на более мелкие объекты

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

2) Принудительные требования к данным по методу.

public SearchWithTwoLevelCache(ISearchCore s, ICurrentTimeProvider tp) 
{ 
    //Initialize the two levels. 
    S=s; 
    lvl2 = TimeBoundedQueryCache(s.AsQueryDataSource, tp, TimeSpan(24,0,0)); 
    lvl1 = SizeBoundedQueryCache(lvl2, 10); 
} 

Можно утверждать, что это состояние фактически не требует самого класса, так как, если он на самом деле является необходимым условием для функции, то сделать это требование самой функции. Это устраняет двусмысленность. Поэтому

Ваш класс может стать:

public SearchWithTwoLevelCache(ISearchCore s) 
{ 
    S = s; 
} 

public Whatever PerformTwoLevelSearch(ICurrentTimeProvider tp) { } 

Например.

Идея здесь состоит в том, чтобы предоставить только данные в конструкторе, которые абсолютно необходимы для состояния всего класса.

Вы можете, конечно, осуществлять проверки на уровне метода и исключать исключения, но для людей, использующих ваш класс, это может оказаться очень неприятным.Как они знали, что для вызова функции 1 они должны были вызвать конструктор 2 и установить другую переменную? Как они узнают, какой интерфейс использовать? Вот почему сделать это условие функции намного проще и для использования, и для поддержания.

В будущем это также затруднит расширение этого класса. Если успех метода основан на вызове нескольких других методов или конструктора, то рефакторинг и изменение этой логики также заставят всех ваших клиентов тоже измениться.

+0

Отличный ответ, спасибо! –

1

Вы можете установить publicboolean property внутри класса и в конкретном constructor вы можете сделать это true. Значение по умолчанию этого свойства может быть false.

Так что если объект obj1, вы можете проверить это логическое значение перед вызовом функции.

if(obj1.public_property) 
    // do function call 

Это решение. Там могут быть лучшие решения, чем это.

0

Быстрое решение (не полезно) будет использовать флаг для указания того, какой конструктор вызывается - путем проверки его везде в вашем коде позже.

На самом деле вам нужно Discriminated Unions в F #. Но поскольку в C# мы не имеем этого, вы должны абстрагировать свой класс до interface, а затем предоставить различные конкретные реализации для этого интерфейса.

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