#java #solid-principles #dependency-inversion
#java #solid-принципы #зависимость-инверсия
Вопрос:
извините за длинный вопрос, а также за мой английский.
Я читаю статью о DIP. Я обобщу код здесь.
interface CoffeeMachine() {
void brewFilterCoffee();
}
interface EspressoMachine() {
void brewEspressoCoffee();
}
Они создают две разные кофейные машины. BasicCoffeeMachine и PremiumCoffeeMachine. Они оба имеют одну и ту же функцию — brewFilterCoffee(); поэтому они помещают ее в интерфейс CoffeeMachine
class BasicCoffeeMachine implements CoffeeMachine {
@Override
void brewFilterCoffee() {
System.out.println("brewing filter coffee...");
}
}
// this one can make Espresso
class PremiumCoffeeMachine implements CoffeeMachine, EspressoMachine {
@Override
void brewFilterCoffee() {
System.out.println("brewing filter coffee but in premium way...");
}
@Override
void brewEspressoCoffee() {
System.out.println("brewing espresso coffee...");
}
}
Когда они создают CoffeeApp, он принимает интерфейс CoffeeMachine в конструкторе и использует его для prepareCoffee ()
class CoffeeApp {
CoffeeMachine machine;
public CoffeeApp(CoffeeMachine machine) {
this.machine = machine;
}
public void prepareCoffee() {
machine.brewFilterCoffee();
}
}
В основном классе.
class Main {
public static void main(String[] args) {
PremiumCoffeeMachine premiumCoffeeMachine = new PremiumCoffeeMachine();
CoffeeApp app = new CoffeeApp(premiumCoffeeMachine);
app.brewFilterCoffee();
}
}
Я оставил здесь в замешательстве, потому что они не упомянули, как они используют brewEspressoCoffee() в CoffeeApp.
Итак, я продолжаю и модифицирую CoffeeApp следующим образом:
class CoffeeApp {
public void prepareFilterCoffee(CoffeeMachine machine) {
machine.brewFilterCoffee();
}
public void prepareEspressoCoffee(EspressoMachine machine) {
machine.brewEspressoCoffee();
}
}
В основном классе, если я хочу brewEspressoCoffee() , я просто создаю экземпляр, который реализует EspressoMachine
class Main {
public static void main(String[] args) {
PremiumCoffeeMachine premiumCoffeeMachine = new PremiumCoffeeMachine();
CoffeeApp app = new CoffeeApp();
app.brewEspressoCoffee(premiumCoffeeMachine);
}
}
Это все еще следующий провал? И есть ли какой-нибудь лучший способ приблизиться, чем этот пример? Любой пример будет оценен.
Спасибо!!
Комментарии:
1. @Fildor не путайте DI (внедрение зависимостей) с DIP (принцип инверсии зависимостей), DIP говорит не о внедрении, а просто об использовании абстракции (например
interface
, likeCoffeeMachine
) вместо фактической реализации (напримерBasicCoffeeMachine
, )2. Спасибо за ответ. @Lino Итак, я правильно следую DIP?
3. @ABC я бы так сказал, поскольку
CoffeApp
не зависит от реализации (т. Е.class
), А исключительно от абстракции (т. Е.interface
)4. @Lino, о котором я упоминал… «и с зависимостями от конкретных классов сверху» .
5. @Lino … но я был неправ. Перепутал интерфейсы для классов.
Ответ №1:
Я думаю, вы уловили суть DIP, которая заключается в том, что вы всегда можете вставить интерфейс, чтобы инвертировать направление зависимости.
Помимо простого следования за провалом, здесь также следует учитывать принцип сокрытия информации. Мы часто думаем о IH применительно к данным, но это относится и к зависимостям.
В оригинале CoffeeApp
клиент (customer) не имеет зависимости от EspressoMachine
и косвенной (транзитивной) зависимости от CoffeeMachine
. В модифицированном CoffeeApp
клиент имеет прямые зависимости от обоих машинных интерфейсов.
Эти зависимости основаны на абстракциях, поэтому провал удовлетворен; но возникает вопрос, если CoffeeApp
он предоставляет свои зависимости своим клиентам, то какова его цель? Клиенты могут напрямую вызывать эти зависимости. Передавая его зависимости, CoffeeApp
становится бесполезным.