Какой шаблон проектирования использовать, когда я хочу, чтобы только некоторые производные классы имели доступ к методу в базовом классе? - PullRequest
1 голос
/ 11 июля 2011

У меня есть уникальная проблема / ситуация здесь. Попытка сделать это максимально простым. У меня есть базовый класс (скажем, Parent) и целая куча производных классов (скажем, Child1, Child2 ..ChildN), непосредственно производных от базового класса (Parent). Я хочу изменить базовый класс и добавить «AVeryPrivilegedMethod», который будет доступен только для Child2 и Child3, а не для любых других дочерних (или сделать его настраиваемым так, чтобы в будущем Child5 мог также использовать его в будущем с минимальными изменениями). Какой дизайн / Архитектурный рисунок подойдет для этого счета?

Используемый язык - C #.

PS: я думал об использовании InternalVisibleTo , но понимаю, что это применяется на уровне сборки

Ответы [ 7 ]

4 голосов
/ 11 июля 2011

Я не понимаю, как это связано с «шаблонами проектирования» - это просто вопрос языковых особенностей. В C # нет языковой функции, которая позволяет легко инкапсулировать подобный тип.

Полагаю, вы можете либо добавить новый класс в иерархию, BaseWithExtras, производный от Base, и сделать так, чтобы некоторые дочерние элементы были производными от Base, а другие - BaseWithExtras, либо перестать беспокоиться об этом и просто сделайте метод доступным для всех производных классов.

3 голосов
/ 11 июля 2011

Звучит так, как будто вам не хватает другого абстрактного класса (SpecialChild из-за отсутствия более подходящего имени), который наследуется от Parent, но из которого получены Child2 и Child3.

                    Parent
                      | 
   |------------------|------------|----------|
Child1            SpecialChild   Child4    Child5
                      |
         |---------------------|
      Child2                 Child3

Задайте себе вопрос: что отличается от Child2 и Child3 в том, что они сами имеют общее поведение, но ведут себя по-разному со всеми другими детьми?SpecialChild моделирует то поведение и в примере, который вы привели в своем вопросе, было бы местом для реализации AVeryPrivilegedMethod.

3 голосов
/ 11 июля 2011

Вы хотели бы сделать еще один уровень абстракции:

public class Parent { }
public class MethodContainer : Parent { public void SomeMethod() { } }

Тогда каждый дочерний класс наследует соответствующий класс:

// Does not have method
public class ChildA : Parent

// Has Method
public class ChildB: MethodContainer
0 голосов
/ 13 декабря 2011

Если эти методы будут использоваться только в определенных дочерних классах, включая их в иерархию наследования, это не выглядит хорошей идеей.Здесь мы хотим достичь повторного использования реализации, поэтому хорошая идея - это внедрение через внедрение зависимостей, однако, если вам нужно представить этот метод как часть интерфейса ваших классов, тогда Mixin (если бы это было возможно в C #)пойти на.

0 голосов
/ 11 июля 2011

Как насчет старой доброй ассоциации с Dependency Injection (так что вы можете изменить ее позже, если необходимо, чтобы другие классы получили доступ к функциям).

public class Parent {
   private PrivilegedFunctions p;
   public Parent(PrivilegedFunctions inP) { p = inP; }
}

public interface PrivilegedFunctions {
   void SomeFuncHere();
}

public class AllowPrivileges : PrivilegedFunctions {
   public void AllowPrivileges () { }

   public void SomeFuncHere()
   { 
      // Actual implementation
   }
}

public class NoPrivileges : PrivilegedFunctions {
   public void NoPrivileges () { }

   public void SomeFuncHere()
   { 
      // No implementation
   }
}

public class Child1 : Parent {
   public Child1(PrivilegedFunctions inP) : base(inP) { }
}

Затем, в зависимости от Child, вы можете ввести1004 * или NoPrivileges версия.

// Child with privileges
Child1 with_priv = new Child1(new AllowPrivileges());
with_priv.SomeFuncHere(); // Does privileged operation
// Child without privileges
Child1 without_priv = new Child1(new NoPrivileges());
without_priv.SomeFuncHere(); // Does nothing
0 голосов
/ 11 июля 2011

Вероятно, хороших вариантов нет, так как это не стандартный уровень защиты. Вот один из вариантов

 class Parent
 {
       private void AVeryPrivilegedMethod() {}
       public static void AVeryPrivilegedMethod(Child2 c) { ((Parent)c).AVeryPrivilegedMethod(); }
       public static void AVeryPrivilegedMethod(Child3 c) { ((Parent)c).AVeryPrivilegedMethod(); }
 }

Позже вы называете это так:

 Child2 c = new Child2();
 Parent.AVeryPrivilegedMethod(c);

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

0 голосов
/ 11 июля 2011

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

...