2010-08-12 4 views
5

Ситуация:C# OO дизайн проблема с отключением от методов

Assembly 1 
________________________    ________________________ 
| Class A    |   | Class B    | 
|-----------------------|   |-----------------------| 
| Method someMethod  |---------->| Method otherMethod | 
|      |   |      | 
|_______________________|   |_______________________| 

Ассамблеи 1 представляет собой приложение, которое другие разработчики могут использовать. Мы дадим им только DLL, чтобы мы могли публиковать обновления из приложения, если мы не изменим api. Разработчики не могут изменить структуру в сборке 1

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

Проблема заключается в том, что разработчик не может переопределить otherMethod из класса B, , он может переопределить его, но класс A всегда будет вызывать метод из класса B, а не переопределенный метод.

Assembly 1 
________________________    ________________________ 
| Class A    |   | Class B    | 
|-----------------------|   |-----------------------| 
| Method someMethod  |----XX---->| Method otherMethod | 
|      |   |      | 
|_______________________|   |_______________________| 
       \         | 
       \         | 
        \         | 
Assembly 2   \         | 
        \    ________________|_______ 
        \    | Class ExtendedB  | 
         \    |-----------------------| 
         \____________>| Method otherMethod | 
            |      | 
            |_______________________| 

Ассамблея 2 имущие ссылку на сборку 1

Частичный класс не работает, потому что она должна быть такой же, монтаж и не будет работать над 2

Существуют шаблоны проектирования для этой проблемы? Или есть другое решение с отражением или что-то в этом роде?

EDIT Добавлен пример кода:

/* ASSEMBLY 1 */ 

namespace Assembly1 
{ 
    public interface IAService 
    { 
     void TestMethod3(); 
     void TestMethod4(); 
    } 

    public interface IBService 
    { 
     void TestMethod1(); 
     void TestMethod2(); 
    } 

    public class AService : IAService 
    { 
     // Base implementation of AService 
     public virtual void TestMethod3() 
     { 
      //do something 
     } 
     public virtual void TestMethod4() 
     { 
      //do something 
     } 
    } 

    public class BService : IBService 
    { 
     // Base implementation of BService 
     public virtual void TestMethod1() 
     { 
      //do something 
     } 
     public virtual void TestMethod2() 
     { 
      //need to call AService implementation from assembly 2 
     } 
    } 
} 





/* ASSEMBLY 2 */ 
namespace Assembly2 
{ 
    public class NewAService : AService 
    { 
     public override void TestMethod3() 
     { 
      //default implementation which could be overridden 
      base.TestMethod3(); 
     } 

     public override void TestMethod4() 
     { 
      //default implementation which could be overridden 
      //An implementation of IBService Should be called 

      base.TestMethod4(); 
     } 
    } 
} 
+0

Как вы называете метод класса B? Доступен ли он статически? Составляет ли сборка 2 (или любая другая сборка) объект типа ExtendedB в класс A (инъекция зависимостей)? – dbemerlin

+1

Не могли бы вы предоставить фрагмент кода? Диаграммы не очень хорошо описывают * использование *. – DevinB

+0

Люди, почему мы предлагаем реализацию интерфейса, прежде чем мы поймем, почему наследование не позволяет полиморфизм? –

ответ

4

вы должны реорганизовать

public interface IClassB 
{ 
    void SomeMethod(); 
} 
public Class A 
{ 
    private IClassB myInstanceB = new ClassB(); 

    public ClassA(){} 

    public ClassA(IClass B) 
    { 
     myInstanceB = B; 
    } 

    public void SomeMethod() 
    { 
     myInstanceB.SomeMethod(); 
    } 
} 

public ClassB : IClassB 
{ 
    public void SomeMethod() 
    { 
     // some wicked code here... 
    } 
} 

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

использование в сборке 2 буду что-то вроде этого

public class NewFunctionalityClass : IClassB 
{ 
    public void SomeMethod() 
    { 
     //something else 
    } 
} 
public TestClass() 
{ 
    public void ShowMethod() 
    { 
     var defaultObject = new ClassA(); 
     defaultObject.SomeMethod(); // default implementation 

    var otherObject = new ClassA(new NewFunctionalityClass()); 
    otherObject.SomeMethod(); // here the new implementation will run 
    } 
} 
+0

Я не вижу, как это помогает. –

+0

, так что вы можете легко добавить новые функциональные возможности в assembly2 – nWorx

+0

Я добавил вам пример кода Это помогает, потому что вам больше не придется переопределять или виртуализовывать любые методы -> проще – nWorx

0

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

0

Существует несколько шаблонов дизайна, которые могут работать. Вот список, который пришел мне на ум (в этом порядке) во время чтения вашего сообщения.

  1. ADAPTER
  2. DECORATOR
  3. TEMPLATE METHOD.
+0

Это не объясняет, почему звонок, по-видимому, практически не разрешается. Давайте диагностируем перед назначением. –

3

Предполагая, что A называет экземпляр ExtendedB, на который ссылается через переменную типа B и метод отмечен virtual в B и override в ExtendedB, вызов должен быть полиморфными. Он должен работать. Может быть, вы можете показать какой-то код.

3

Это трудно сказать, без фактического кода, но принимая вашу схему (кстати, любит ASCII искусство!) По номинальной стоимости, я предположил бы, что класс А имеет ссылку на интерфейс, а не жестко кодируется для класса В.

Как это:

// ----- this is in Assembly 1 ----------- 
public ClassA 
{ 
    public MyInterface myDependentObject; 
} 

public interface MyInterface 
{ 
    void OtherMethod(); 
} 

public class ClassB : MyInterface 
{ 
    public void OtherMethod() 
    { 
     // some code here... 
    } 
} 


// ----- this is in Assembly 2 ----------- 
public class OtherB : MyInterface 
{ 
    public void OtherMethod() 
    { 
     // some code here... 
    } 
} 

в сборке 2, назначьте OtherB к ClassA:

// ----- this is in Assembly 2 ----------- 
OtherB b = new OtherB(); 
ClassA a = new ClassA { myDependentObject = b }; 

Теперь, когда ClassA выполняет myDependentObject.OtherMethod(), он будет забрать из узла 2, а не сборки 1 определения ,

НТН ...

+1

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

+0

@Steven, ОП просил шаблон дизайна или подход к лучшей практике. В этом случае я по-прежнему придерживаюсь использования интерфейсов. Также я думаю, что это довольно очевидно, почему это не сработает - ClassA устанавливает жесткую зависимость от ClassB где-то в сборке 1. Другими словами, у нас есть проблема «разделения проблем». Интерфейсы - лучший подход для обработки этих случаев, поскольку он ослабляет зависимость и позволяет им быть разрешенными дальше в процессе (т. Е. В сборке 2 в моем примере). – code4life

+0

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

1

Можете ли вы предоставить некоторые сократить код примера? Я ценю искусство ascii, но я подозреваю, что проблема может заключаться в том, как A получает B, в котором он работает. Если он создает экземпляр собственной копии, то нет способа вызвать переопределенный метод в производном классе.

При этом я также согласен с тем, что рефакторинг интерфейса, предлагаемый другими, - это путь. Разрешить A работать с интерфейсом IB, поэтому он должен использовать предоставленного исполнителя IB, а не генерировать его. Таким образом, не имеет значения, является ли предоставленный объект B, подклассом B или чем-то еще полностью. Он также делает подклассы A, B и Bs более проверяемыми, что является хорошей вещью.

+0

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

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