C # OO проблема дизайна с переопределением из методов - PullRequest
5 голосов
/ 12 августа 2010

Ситуация:

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

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

РЕДАКТИРОВАТЬ Добавлен пример кода:

/* 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();
        }
    }
}

Ответы [ 6 ]

4 голосов
/ 12 августа 2010

вы должны выполнить рефакторинг

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
   }
}
3 голосов
/ 12 августа 2010

Трудно сказать без фактического кода, но, взяв вашу диаграмму (кстати, любите искусство ASCII!) За чистую монету, я бы предположил, что в классе A есть ссылка на интерфейс, а не жестко Класс Б.

Как это:

// ----- 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.

НТН ...

3 голосов
/ 12 августа 2010

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

1 голос
/ 12 августа 2010

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

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

0 голосов
/ 12 августа 2010

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

  1. ADAPTER
  2. DECORATOR
  3. TEMPLATE METHOD
0 голосов
/ 12 августа 2010

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

...