2016-04-03 13 views
0

Посмотрите на этот класс, пожалуйста:Принцип Open/Closed говорит, что мы не можем изменять интерфейсы наших классов?

public class SomeClass { 

public void method1(){ 
    // do something 
} 

public void method2(){ 
    // do something 
} 

} 

Далее, представьте, что 10 классов наследует этот класс. Итак, если мы добавим параметр to method1(), например, мы должны изменить 10 классов. Это противоречит принципу Open/Closed. Итак, принцип Open/Closed говорит, что мы не можем изменить публичный интерфейс наших классов?

+1

Вы должны изменить более чем на 10 классы. Вы должны изменить каждый класс, который будет * вызывать * 'method1()', потому что ни один из этих вызовов с 0 аргументами недействителен. Я бы не стал так беспокоиться об OCP как простой обратной совместимости. Конечно, если вы контролируете весь код вызова, все в порядке. Это действительно зависит от контекста. –

+1

http://programmers.stackexchange.com/questions/310603/is-it-appro-to-not-follow-the-oc-principle-if-you-have-unit-test-coverage –

+0

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

ответ

0

Да - вроде ... # 8> P

«Closed изменения» бит говорит, что вы не должны удалить public void method1() подпись и не изменяет свою семантику (которые должны быть поставлены все правильно реализации конкретные классы).

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

public class SomeClass { 

    @Deprecated 
    default public void method1(){ 
     method1(#SENTINAL#); 
    } 

    public void method1(#TYPE# arg){ 
     if (arg == #SENTINAL#) { 
      // do something old 
     } else { 
      // do something new 
     } 
    } 

    public void method2(){ 
     // do something 
    } 

} 

ПРИМЕЧАНИЕ: Этот подход может не работать, если аргумент не имеет полезный # Sentinal # значение, например, это int и все значения действительны. Часто, однако, есть кое-что, как и любое отрицательное, значение MIN или MAX, пустой или нулевой объект, и т.д. Если нет такого Sentinal нет в наличии, вы можете создать частный общий метод, как:

public class SomeClass { 

    @Deprecated 
    default public void method1(){ 
     method1(true); 
    } 

    public void method1(#TYPE# arg){ 
     method1(false, arg) 
    } 

    private void method1(boolean isOldWay, #TYPE# arg) { 
     if(isOldWay) { 
      // snore - still old clients 
     } else { 
      // yea! new clients are much greener! 
     } 
    } 
} 

PS - Я говорю «интерфейс», даже если вы используете класс. Подумайте об интерфейсе как об открытых элементах класса, объявленных одновременно с реализацией класса. Обычно я предпочитаю использовать код-интерфейс, но это не вопрос OP, и он не изменит мою точку зрения (просто , где были внесены изменения - esp при использовании реализаций интерфейса Java 8 по умолчанию).

+0

Я не согласен с тем, что «Open to extension» позволяет вам изменять интерфейс - вам может потребоваться время от времени, но это нарушает OCP, а не часть. OCP говорит, что если вам нужно реорганизовать и модифицировать, вы сделаете это таким образом, который открыт для будущего расширения. например через что-то вроде шаблона посетителя/стратегии. См. Также [эта статья Дядюшки Боб] (https://blog.8thlight.com/uncle-bob/2014/05/12/TheOpenClosedPrinciple.html) – anotherdave

+0

Ну, это немного раскалывает волосы, но я думаю, что до тех пор, пока клиентские коды не нуждаются в изменении, это нормально (в лучшем случае перекомпилировано, но даже не одна скобка, сглаженная в праведный парик * :: smile :: *). Правда, это что-то вроде нарушения «чистого» OCP, но я достаточно прагматичен, чтобы думать, что дух поддерживается *** полностью *** совместимыми изменениями интерфейса - не потому, что методы по умолчанию действительно сделали это на любом языке? (Слишком плохо, что мы не можем сделать их «default final» ... * :: haha ​​:: *) – Stevel

+0

уверен, прагматизм всегда ключевой (это тоже потому, что это «принцип», а не «правило» - это запах кода, чтобы нарушить его, но это не значит, что это никогда не должно быть сделано). – anotherdave

0

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

public class SomeClass{  
    IProvider _provider; 

    public SomeClass(IProvider provider){ 
     _provider = provider 
    } 

    public void method1(){ 
     var someInput = _provider.Get(); 
     // do something 
    } 

    public void method2(){ 
     var someInput = _provider.Get(); 
     // do something 
    } 
}