Проблема проектирования - Является ли Inheritance правильным способом упростить этот код? - PullRequest
7 голосов
/ 24 августа 2010

У меня есть проблема с дизайном, которую я хотел бы решить.У меня есть интерфейс, давайте назовем его IProtocol, который реализуется двумя отдельными классами.Мы смотрим более 600 строк кода здесь.Подавляющее большинство того, что они делают, - то же самое, за исключением для некоторых конкретных областей, таких как DiffStuff();

Текущая структура выглядит примерно так:

public class Protocol1 : IProtocol
{
  MyInterfaceMethod1()
  {
     Same1();
     DiffStuff();
     Same2();
  }
}

И

public class Protocol2 : IProtocol
{
  MyInterfaceMethod1()
  {
     Same1();
     Same2();
  }
}

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

Я рассматриваю вопрос об изменении реализации Protocol1 для наследования от protocol2, например, так (Protocol2 в основном останется прежним, за исключением того, что мне придется обернуть Same1() и Same2() в частные методы.)

public class Protocol1 : Protocol2
{
  void Same1()
  {
     base.Same1();
  }

  void Same2()
  {
     base.Same2();
  }

  MyInterfaceMethod1()
  {
     Same1();
     DiffStuff();
     Same2();
  }
}  

Правильный ли это способ решения этой проблемы?

Редактировать: Многие люди помогли мне с этим вопросом, спасибо за ясное понимание.В моем случае два объекта не относятся к одному и тому же типу, хотя большая часть их реализации является общей, поэтому я пошел с предложением Бобби использовать абстрактный базовый класс, создавая небольшие методы для инкапсуляции изменений между классами,Дополнительная благодарность:

  • Жлобер
  • Ганс Пассант
  • Джефф Стерн

Ответы [ 6 ]

7 голосов
/ 24 августа 2010
    /// <summary>
    /// IProtocol interface
    /// </summary>
    public interface IProtocol
    {
        void MyInterfaceMethod1();
        void Same1();
        void Same2();
    }

затем ...

public abstract class ProtocolBase : IProtocol
{
    #region IProtocol Members

    public void MyInterfaceMethod1()
    {
        // Implementation elided...
    }

    public void Same1()
    {
        // Implementation elided...
    }

    public void Same2()
    {
        // Implementation elided...
    }

    public abstract void DiffStuff();

    #endregion
}

наконец ...

public sealed class Protocol1 : ProtocolBase
{
    public override void DiffStuff()
    {
        // Implementation elided...
    }
}

public sealed class Protocol2 : ProtocolBase
{
    public override void DiffStuff()
    {
        // Implementation elided...
    }
}
5 голосов
/ 24 августа 2010

Не совсем. Нет смысла добавлять методы Same1 и Same2, вы наследуете их от ProtocolBase. И DiffStuff () должен быть виртуальным методом, чтобы вы могли переопределить его и задать другое поведение.

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

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

Однако вы должны рассмотреть возможность использования композиции вместо наследования. Два подхода имеют разные преимущества и недостатки , но состав часто (обычно?) Лучше *:

 public class Protocol {

      private ISpecialHandler specialHandler;

      public Protocol() {}

      public Protocol(ISpecialHandler specialHandler) {
          this.specialHandler = specialHandler;
      }

      void Same1() {}
      void Same2() {}

      public void DoStuff() {
          this.Same1();
          if (this.specialHandler != null) {
              this.specialHandler.DoStuff();
          }
          this.Same2();
      }
 }

Затем вызывающие абоненты могут передавать экземпляры объектов ( стратегии ), которые предоставляют специализированные алгоритмы для обработки любого имеющегося случая:

 Protocol protocol1 = new Protocol(new DiffStuffHandler());
 protocol1.DoStuff();

* См. Patterns I Hate # 2: Template Template для подробного объяснения того, почему в вашем случае состав обычно лучше, чем наследование.

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

Возможно, вы захотите подумать, работает ли этот тип шаблона:

public class ProtocolHelper
{
    public void Same1() {}
    public void Same2() {}
}

public class Protocol1 : IProtocol
{
    private readonly ProtocolHelper _helper = new ProtocolHelper();

    void MyInterfaceMethod1()
    {
        _helper.Same1();
        DiffStuff();
        _helper.Same2();
    }
}

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

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

Я лучше проектирую (на мой взгляд)

public abstract class Protocol_common : IProtocol 
{ 
  MyInterfaceMethod1() 
  { 
     Same1(); 
     DiffStuff(); 
     Same2(); 
  } 

  abstract void DiffStuff();

}

public class Protocol1 : Protocol_common
{ 
  DiffStuff() 
  { 
      /// stuff here.
  } 
}

public class Protocol2 : Protocol_common
{ 
  DiffStuff() 
  { 
      /// nothing here.
  } 
}

(Это на самом деле больше псевдокода, чем собственно C #, но я достиг вершин)

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

Я согласен с MathEpic.Я бы использовал Шаблонный метод шаблон.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...