2015-04-21 4 views
1

Я преподаю принципы, связанные с S.O.L.I.D. Объектно-ориентированное программирование и у меня возникают проблемы с пониманием всех подробностей в письме DПринцип инверсии зависимостей (применительно к Java)

Я читаю его запись в Википедии (http://en.wikipedia.org/wiki/Dependency_inversion_principle), и я не понимая, все, что ставится на диаграмме (Dependency-Inversion Принцип.):

http://en.wikipedia.org/wiki/Dependency_inversion_principle#/media/File:DIPLayersPattern_v2.png)

Я заметил, есть два типа стрел - один пунктирные и один твердое тело.

Основываясь на моем понимании, пунктирная линия представляет собой эквивалент ключевого слова «реализует» в Java, а сплошная линия представляет ключевое слово «extends».

Это правильная интерпретация?

ответ

3

Это может прояснить несколько вещей:

Explanation of the UML arrows

Примечание Изображения для Visual Studio, но я думаю, что бы наиболее информации будет эквивалентна с большинством UML документации.

пунктирная линия представляет собой эквивалент «орудий»

Именование сущностей в UML бросает мне немного тоже ... похоже, что Policy зависит от интерфейса, который описывает договор с модулем нижнего уровня Mechanism

Однако на второй (сплошной линии), которая должна представлять собой наследование (по крайней мере, я полагаю). Mechanism реализует интерфейс (абстракция) Policy, а не до применения DIP, когда Policy ссылается на бетон Mechanism.

То, что он пытается передать в основном, классы не должны зависеть от других классов, однако они могут зависеть от абстракций (интерфейсов), а не от бетонов.

Самый простой пример: Оригинальный Foo/Logger с зависимостями от модулей нижнего уровня.

// "Low level Module" Mechanism equivilant 
public class Logger { 
    public void logInformation(String logInfo) { 
     System.out.println(logInfo); 
    } 
} 

// "High level module" Policy equivalent. 
public class Foo { 
    // direct dependency of a low level module. 
    private Logger logger = new Logger(); 

    public void doStuff() { 
     logger.logInformation("Something important."); 
    } 
} 

В приведенном выше описании, Foo зависит от конкретной реализации Logger. Это может быть переработано как таковое (примечание есть несколько способов сделать это, это только один)

public interface ILogger { 
    void logInformation(String logInfo); 
} 

public class Logger implements ILogger { 
    @Override 
    public void logInformation(string logInfo) { 
     System.out.println(logInfo); 
    } 
} 

public class Foo { 
    private ILogger logger; 
    public void setLoggerImpl(ILogger loggerImpl) { 
     this.logger = loggerImpl; 
    } 

    public void doStuff() { 
     logger.logInformation("Something important."); 
    } 
} 

В этом реорганизовать, Foo больше не зависит от Logger, но теперь использует интерфейс ILogger - это означает, что вам может переключаться в и из реализаций ILogger во время выполнения, объект конкретизации и т.д.

Вы могли бы потреблять Foo как таковой:

Foo foo = new Foo(); 
ILogger logger = new Logger(); 
foo.setLoggerImpl(logger); 
foo.doStuff(); 

Это, конечно, печать для консоли «Что-то важное».Теперь, что произойдет, если вы не хотите регистрироваться на консоли, а в базе данных?

public class LoggerToDb implements ILogger { 
    @Override 
    public void logInformation(string logInfo) { 
     DbContext databaseContext = new DbContext(); 
     databaseContext.insertLog(logInfo); 
    } 
} 

и теперь можно употреблять в пищу:

Foo foo = new Foo(); 
ILogger logger = new LoggerToDb(); 
foo.setLoggerImpl(logger); 
foo.doStuff(); 

Обратите внимание, как ничего не было изменить в Foo реализации, поскольку Foo не зависит от Logger, но вместо ILogger - с таким подходом мы можем обеспечить новая конкреция с абстракцией, и замените ее на Foo, даже не касаясь Foo! Довольно неато ИМО.

Примечание: в приведенных выше примерах я создаю объект и предоставляю реализацию, это также можно сделать с помощью инфраструктуры IOC, такой как Spring Java.

+0

@LuiggiMendoza спасибо, никогда бы не получил этот синтаксис правильно :) – Kritner

+0

Я думаю, что вы смешиваете инъекцию зависимостей и инверсию зависимостей. DIP применяется к межмодульным зависимостям и является улучшением по сравнению с стандартной многоуровневой архитектурой. Основное внимание уделяется отношениям между модулями. [Более подробная информация здесь] (https://books.google.ca/books?id=X7DpD5g3VP8C&pg=PA123&lpg=PA123&dq=improved+layered+architecture+dependency+inversion+principle&source=bl&ots=tRBNLGD9YS&sig=8Zrz_2ANj29vXYNnEAHssA95dGI&hl=fr&sa=X&ei=dD44VdfdGozToAThh4HwAQ&ved= 0CCgQ6AEwAQ # v = onepage & q = улучшенный% 20layered% 20architecture% 20dependency% 20inversion% 20principle & f = false) – plalx

+0

@plalx hmm ... У меня создалось впечатление, что DI - это один из способов выполнения DIP - я специально не называл это в своем пример (как он был вызван в цитированной статье wiki), но 'ILogger' принадлежит« Foo', а не «Logger» или любые другие реализации «ILogger». Из того, что я прочитал, который описывает DIP ... можете ли вы прояснить, что пропустили? – Kritner

3

Пунктирная линия означает зависимость от исходного кода. Сплошная линия с пустым треугольником означает особый тип зависимости: наследование класса или реализация интерфейса.

На этой диаграмме служба службы сервиса и механизма обслуживания - это абстракции, а Policy Service - абстракция более высокого уровня. Механизм и утилита - это детали.

Политика имеет очевидную зависимость от Механизма и Утилиты (поток управления, начиная с Политики, достигнет этих деталей), а на более низком уровне. Механизм имеет аналогичную зависимость от времени работы от Utility. Однако на уровне исходного кода политика зависит только от службы политики, а механизм также зависит от службы политики. Это инверсия зависимостей.