2009-09-11 3 views
0

OCP (открытый/закрытый принцип) является одним из принципов SOLID. Который говорит:Как такой важный принцип «OCP» станет причиной масштабной практики дублирования кода?

«Программные Сущности должны быть открыты для расширения, но закрыты для модификации.»

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

Как такой важный принцип «OCP» станет причиной масштабной практики дублирования кода?

namespace SOLIDPrinciples 
{ 
    public class ReportFormatter { 
     public virtual void FormatReport() { 
      Console.WriteLine("Formatting Report for 8-1/2 X 11 ...."); 
     } 
    } 

    public class TabloidReportFormatter : ReportFormatter { 
     public override void FormatReport() { 
      Console.WriteLine("Formatting Report for 11 X 17 ...."); 
     } 
    } 
} 

Я пропустил что-то здесь? Есть ли способ объяснить OCP?

+0

Что такое дублирование в приведенном выше коде? – shahkalpesh

+1

Ваш код не является примером OCP. Возможно, вы показываете проект, который «открыт для расширения», но где находится «закрытая для модификации»? – SingleShot

+0

@SingleShot: для части «закрыта для модификации», я думаю, что первый класс должен быть внутренним, а не публичным. Правильно???? – egyamado

ответ

4

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

Пример, который вы предоставляете, на самом деле не демонстрирует принцип Open/Closed, поскольку вы не продемонстрировали, как поведение данного класса может быть расширено без изменений. Принцип Open/Closed заключается в создании новых классов каждый раз, когда желателен вариант поведения. Это может быть достигнуто с использованием наследования вместе с шаблоном метода шаблона (т.е. вызовом абстрактных или виртуальных методов в базовом классе, которые переопределены в подклассах для достижения желаемого/нового поведения), но чаще это демонстрируется с использованием композиции с использованием шаблона стратегии (т.е. инкапсулируя поведение варианта в классе и передавая его закрытому типу, который будет использоваться при определении общего поведения).

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

public class ReportWriter : IReportWriter 
{ 
    Write(IReportData data, IReportFormatter reportFormatter) 
    { 
     // ... 

     var formattedStream = reportFormatter.Format(data, stream); 

     // ... 
    } 
} 

Просто ради демонстрации, я сделал несколько предположений о том, как наш новый форматировщик может вести себя, так что не уделяют слишком сильно на этой части. Основное внимание уделяется тому, что ReportWriter открыт для расширения, позволяя передавать новые форматы, что влияет на то, как отчеты в конечном итоге записываются, но закрыты для модификации кода, необходимого для достижения этого нового поведения (т. Е. Наличия операторов if, switch заявления и т. д., чтобы добиться нескольких способов форматирования).

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

+0

Неправильно. Типичное применение OCP включает в себя создание подкласса с другой реализацией для некоторого переопределяемого метода, что и есть пример в вопросе. –

+2

Фактически, OCP обычно демонстрируется с использованием композиции, а не наследования. Как я уже сказал, OCP может быть достигнуто с использованием наследования с использованием шаблона метода шаблона, но каждый экземпляр полиморфизма не является примером OCP. Все, что показано в приведенном выше примере, это базовая виртуальная диспетчеризация (т. Е. Переопределение метода). Чтобы продемонстрировать OCP, вы должны показать, как поведение может быть повторно использовано (не полностью заменено), используя точки расширения, такие как шаблон шаблона шаблона или, лучше, шаблон стратегии. –

0

То, что у вас есть, выглядит прекрасно для меня. Вы не изменяли ReportFormatter, вы расширили его.

+0

«FormatReport» здесь не дублируется? Это только один метод, примерно 10 или 100 способов. Я не прав? Если да, могу ли я получить больше разъяснений здесь, пожалуйста. – egyamado

+0

Я считаю, что вам не хватает принципа. Попробуйте это: вернитесь к тому, что у вас было, прежде чем пытаться применить OCP. Затем просмотрите код, который использует ваш ReportFormatters. Назовем это «ReportCreator». Теперь представьте себе создание нового вида форматирования. Если вам нужно изменить «ReportCreator», чтобы добавить новый ReportFormatter, вы нарушили OCP. OCP не означает «использование наследования». – SingleShot

0

Что-то вроде этого можно решить с помощью лучшего дизайна методов. Вместо этого учтите следующее:

namespace SOLIDPrincibles 
{ 
    public class ReportFormatter { 
     public virtual void FormatReport(String size) { 
       Console.WriteLine("Formatting Report for " + size + " ...."); 
     } 
    } 

    public class TabloidReportFormatter : ReportFormatter { 
     public override void FormatReport() { 
       super.FormatReport("11 X 17"); 
     }  
    } 
} 

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

+0

Я предполагаю, что эти Консольные выходы являются заполнителями для некоторого реального кода, который делает его фактическое форматирование, поэтому то, что вы предлагаете, может не иметь смысла. Если код действительно должен использоваться как есть, я бы взял то, что вы сделали, и перевернул все это в один класс, который имеет «сеттер» для reportFormat, а не имеет какое-либо наследование. – SingleShot

0

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

Почему у вас есть класс форматирования для каждого формата, когда вы даете формат в качестве аргумента конструктору? Класс formter ctor (или даже метод статического формата класса ReportFormatter) должен иметь отчет и описание формата в качестве аргументов и форматировать отчет соответствующим образом.

Для каждого формата просто нет необходимости в классе.

0

Что-то вроде этого должно работать.

namespace SOLIDPrinciples 
{ 
    public class ReportFormatter { 
     public virtual void FormatReport() = 0; 
    } 

    public class VariableSizeReportFormatter : ReportFormatter { 
     public void SetSize(String size); 
     public override void FormatReport() { 
       Console.WriteLine("implement generic layout routines"); 
     }  
    } 

    public class TabloidReportFormatter : VariableSizeReportFormatter { 
     public override void FormatReport() { 
       // currently, we just do a tweaked version of generic layout .. 
       SetSize("11x7"); 
       Super.Format(); 
       Console.WriteLine("RemoveThatColumnWeDontWant"); 
     }  
    } 
} 

Это означает, что:

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

Это Третья точка, которая является ключом: вы можете сказать «в принципе, разумная макета должна знать, чтобы отбросить год с даты, если комментарий делает строку слишком большой, чтобы она соответствовала». Но реализация этого изменения на практике может быть кошмаром, если это означает, что тогда другой отчет выходит из строя, поэтому вам нужно изменить логику того, как все это работает, а затем повторить каждый макет отчета в системе ...

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

  • Нет связанных вопросов^_^