Форум программистов, компьютерный форум, киберфорум
ООП и паттерны
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск Заказать работу  
 
Рейтинг 4.67/9: Рейтинг темы: голосов - 9, средняя оценка - 4.67
88 / 86 / 55
Регистрация: 14.11.2015
Сообщений: 1,099

[Dependency Inversion] Детали должны зависить от абстракций

16.04.2020, 14:55. Показов 2044. Ответов 7
Метки нет (Все метки)

Студворк — интернет-сервис помощи студентам
Про какую зависимость здесь идет речь? Что классы в идеале должны реализовывать какой-то интерфейс, чтобы подобные классы потом можно было заменять друг-другом в каком-то более high-level модуле?

Как по мне, немного странная формулировка, т.к для меня "детали/деталь" это уже имплементация какой-то абстракции. Было бы правильнее сказать, что классы впринципе должны зависить от какой-то абстракции если бизнес логика подразумевает наличие подобных классов с немного другой реализацией?
0
Лучшие ответы (1)
IT_Exp
Эксперт
34794 / 4073 / 2104
Регистрация: 17.06.2006
Сообщений: 32,602
Блог
16.04.2020, 14:55
Ответы с готовыми решениями:

Inversion Of Control и Dependency Inversion Principle - в чем отличие?
Inversion Of Control и Dependency Inversion Principle.Это одно и тоже или имеются какие-то отличия?

От этой 3аDA4и зависить моя отестация
населения увеличивается на Х% в год через сколько лет населения утроется !!!!!! Надо в PASCALe!!!!! Зарание СПАСИБО!!!!!!

Inversion of Control
объясните прям на пальцах, что значит этот термин Inversion of Control. На сайтах прочел, не могу понять, что он значит. Заранее спасибо

7
Эксперт функциональных языков программированияЭксперт Java
 Аватар для korvin_
4575 / 2774 / 491
Регистрация: 28.04.2012
Сообщений: 8,765
16.04.2020, 18:34
Цитата Сообщение от Artmal Посмотреть сообщение
Про какую зависимость здесь идет речь?
Про зависимость класса от деталей реализации.

Например, у тебя есть класс

Code
1
2
3
4
5
6
class person_a (name : string) (age : int) = object
 
    method serialize_to_string =
        Printf.sprintf "{ name = \"%s\" ; age = %d }" name age
 
end
— метод serialize_to_string «статично» зависит от формата. Если мы захотим сериализовать объект person_a, например в JSON, то нужно будет писать новый метод. И ещё метод для XML. И ещё кучу методов для всех возможных форматов. Кроме большого количества кода мы получим, что класс person_a зависит от кучи других классов и библиотек. И так для всех остальных классов в нашем модуле.

Чтобы упростить архитектуру и сделать её более гибкой, мы абстрагируемся от формата:

Code
1
2
3
4
5
6
7
8
9
10
11
12
type value =
    | String of string
    | Int of int
 
type property = string * value
 
class person_b (name : string) (age : int) = object
 
    method serialize_to (format : property list -> string) =
        format [ ("name", String name); ("age", Int age) ]
 
end
— теперь наш класс person_b зависит только от обощённого интерфейса format : property list -> string. А разные реализации этого интерфейса мы выносим в отдельные модули/классы/функции:

Code
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
let properties_string properties =
    let value_string value = match value with
        | String s -> "\"" ^ s ^ "\""
        | Int i    -> string_of_int i
    in
    let property_string (name, value) = name ^ " = " ^ (value_string value) in
    let concat_property str prop = str ^ " ; " ^ property_string prop in
    match properties with
    | []    -> "{}"
    | p::ps -> "{ " ^ List.fold_left concat_property (property_string p) ps ^ " }"
 
let json_object_string properties =
    let value_string value = match value with
        | String s -> "\"" ^ s ^ "\""
        | Int i    -> string_of_int i
    in
    let property_string (name, value) = "\"" ^ name ^ "\": " ^ (value_string value) in
    let concat_property str prop = str ^ ", " ^ property_string prop in
    match properties with
    | []    -> "{}"
    | p::ps -> "{ " ^ List.fold_left concat_property (property_string p) ps ^ " }"
Теперь мы можем использовать разные форматы, не трогая код класса person_b. Но различные модули/классы/функции форматирования теперь зависят от нашего интерфейса format. Эти зависимость называются инвертированными (обратными).

https://ideone.com/NNSVhS
Миниатюры
[Dependency Inversion] Детали должны зависить от абстракций  
1
88 / 86 / 55
Регистрация: 14.11.2015
Сообщений: 1,099
17.04.2020, 10:16  [ТС]
korvin_, то есть под деталями мы подразумеваем, в данном случае, реализацию какого-то метода класса? И что методы должны принимать как параметр абстракции вместо конкретных имплементаций? Тоже самое получается и с конструкторами класса(предпочитать абстракции)?

Тогда во фразе "Abstractions should not depend on details" мы, получается, всего лишь подразумеваем что интерфейсы/абстрактные классы тоже должны програмироваться(параметры методов) на такие же интерфейсы/абстрактные классы а не на имплементации. И все?

Не по теме:

Btw, делайте как считаете нужным, но, имхо, код на языке, на котором почти никто не пишет здесь на форуме только усложняет понимание, т.к тебе дополнительно нужно гуглить конструкции этого языка и привыкать к новому код стайлу(с последнего сниппета вообще уехал). Уверен, многие бы были благодарны если в будущем сниппеты бы были на Java/C#/JS/C++ или на другом популярном языке.

0
17.04.2020, 10:36

Не по теме:

Цитата Сообщение от Artmal Посмотреть сообщение
Уверен, многие бы были благодарны если в будущем сниппеты бы были на Java/C#/JS/C++ или на другом популярном языке.
Попробуйте переписать на один из этих языков вот этот фрагмент:
Code
1
2
3
type value = 
    | String of string
    | Int of int
Это займет больше места, чем весь код, приведённый в сообщении (требует написания нескольких классов). И вместо размышления о сути, читающие будут вникать в детали реализации.

0
17.04.2020, 10:45  [ТС]

Не по теме:


Цитата Сообщение от Shamil1 Посмотреть сообщение
И вместо размышления о сути, читающие будут вникать в детали реализации.
Осмелюсь предположить, что здесь у вас ошибка проекции. Вы говорите с точки зрения собственного восприятия(возможно обусловленным большим опытом в сфере или опытом изучения подобного кода).

Я же написал с точки зрения начинающего и неискушенного пользователя, которых на форуме явно больше, чем опытных. Я не могу сказать, что код на незнакомом мне языке, поспособствовал моему размышлению о сути. Наоборот, если бы это было оформленно в виде java классов, я бы понял это гораздо быстрее, несмотря на то, что кода вроде как больше.

0
Эксперт функциональных языков программированияЭксперт Java
 Аватар для korvin_
4575 / 2774 / 491
Регистрация: 28.04.2012
Сообщений: 8,765
17.04.2020, 12:05
Цитата Сообщение от Artmal Посмотреть сообщение
то есть под деталями мы подразумеваем, в данном случае, реализацию какого-то метода класса?
Реализацию класса вообще.

Цитата Сообщение от Artmal Посмотреть сообщение
И что методы должны принимать как параметр
Не обязательно как параметр, зависимость может быть инжектирована в конструкторе и храниться в поле объекта. Зависит от конкретного класса.

Цитата Сообщение от Artmal Посмотреть сообщение
Тогда во фразе "Abstractions should not depend on details" мы, получается, всего лишь подразумеваем что интерфейсы/абстрактные классы тоже должны програмироваться(параметры методов) на такие же интерфейсы/абстрактные классы а не на имплементации.
Что?

Вот тебе пример на Java:

Java
1
2
3
4
5
6
7
8
// depends on specific System.out.println
// depends on specific Object.toString
final class Printer {
 
    void print(Object object) {
        System.out.println("Printer: " + object.toString());
    }
}
Извлечём зависимости из класса Printer в отдельные интерфейсы (абстракции):
Java
1
2
3
4
5
6
7
8
9
interface Media {
 
    void print(String s);
}
 
interface Format {
 
    String asString(Object o);
}
Теперь мы можем написать класс Printer, не зависящий от конкретных форматов и устройств печати. Есть 4 разных варианта, выбирай какой тебе будет удобней по ситуации:

Java
1
2
3
4
5
6
final class PrinterA {
 
    void print(Media media, Format format, Object object) {
        media.print("PrinterA: " + format.asString(object));
    }
}
Java
1
2
3
4
5
6
7
8
9
10
11
12
final class PrinterB {
 
    private final Media media;
 
    PrinterB(Media media) {
        this.media = media;
    }
 
    void print(Format format, Object object) {
        media.print("PrinterB: " + format.asString(object));
    }
}
Java
1
2
3
4
5
6
7
8
9
10
11
12
final class PrinterC {
 
    private final Format format;
 
    PrinterC(Format format) {
        this.format = format;
    }
 
    void print(Media media, Object object) {
        media.print("PrinterC: " + format.asString(object));
    }
}
Java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
final class PrinterD {
 
    private final Media media;
    private final Format format;
 
    PrinterD(Media media, Format format) {
        this.media = media;
        this.format = format;
    }
 
    void print(Object object) {
        media.print("PrinterD: " + format.asString(object));
    }
}
Demo

Java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
import com.google.gson.Gson;
 
final class Demo {
 
    static final class Point {
 
        final int x;
        final int y;
 
        Point(int x, int y) {
            this.x = x;
            this.y = y;
        }
 
        @Override
        public String toString() {
            return "Point{x=" + x + ", y=" + y + '}';
        }
    }
 
    private static final Point point = new Point(1, 2);
 
    public static void main(String[] args) {
        System.out.println("---- Stdout:");
 
        printer();
        printerA();
        printerB();
        printerC();
        printerD();
 
        System.out.printf("%n---- Buffer content:%n%s", BUFFER.toString());
    }
 
    static void printer() {
        final var printer = new Printer();
        printer.print(point); // no way to print point neither in any other format nor to any other output device
    }
 
    private static final StringBuilder BUFFER = new StringBuilder();
 
    private static final Media STD_OUT = System.out::println;
    private static final Media BUF_OUT = s -> BUFFER.append(s).append(System.lineSeparator());
 
    private static final Format STRO = Object::toString;
    private static final Format JSON = new Gson()::toJson;
 
    static void printerA() {
        final var printer = new PrinterA();
        printer.print(STD_OUT, STRO, point);
        printer.print(STD_OUT, JSON, point);
        printer.print(BUF_OUT, STRO, point);
        printer.print(BUF_OUT, JSON, point);
    }
 
    static void printerB() {
        final var stdPrinter = new PrinterB(STD_OUT);
        final var bufPrinter = new PrinterB(BUF_OUT);
 
        stdPrinter.print(STRO, point);
        stdPrinter.print(JSON, point);
        bufPrinter.print(STRO, point);
        bufPrinter.print(JSON, point);
    }
 
    static void printerC() {
        final var stroPrinter = new PrinterC(STRO);
        final var jsonPrinter = new PrinterC(JSON);
 
        stroPrinter.print(STD_OUT, point);
        stroPrinter.print(BUF_OUT, point);
        jsonPrinter.print(STD_OUT, point);
        jsonPrinter.print(BUF_OUT, point);
    }
 
    static void printerD() {
        final var printers = new PrinterD[]{
                new PrinterD(STD_OUT, STRO),
                new PrinterD(STD_OUT, JSON),
                new PrinterD(BUF_OUT, STRO),
                new PrinterD(BUF_OUT, JSON)
        };
 
        for (var printer : printers) {
            printer.print(point);
        }
    }
}
Code
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
---- Stdout:
Printer: Point{x=1, y=2}
PrinterA: Point{x=1, y=2}
PrinterA: {"x":1,"y":2}
PrinterB: Point{x=1, y=2}
PrinterB: {"x":1,"y":2}
PrinterC: Point{x=1, y=2}
PrinterC: {"x":1,"y":2}
PrinterD: Point{x=1, y=2}
PrinterD: {"x":1,"y":2}
 
---- Buffer content:
PrinterA: Point{x=1, y=2}
PrinterA: {"x":1,"y":2}
PrinterB: Point{x=1, y=2}
PrinterB: {"x":1,"y":2}
PrinterC: Point{x=1, y=2}
PrinterC: {"x":1,"y":2}
PrinterD: Point{x=1, y=2}
PrinterD: {"x":1,"y":2}


Добавлено через 1 минуту
Цитата Сообщение от Artmal Посмотреть сообщение
Я же написал с точки зрения начинающего и неискушенного пользователя, которых на форуме явно больше, чем опытных. Я не могу сказать, что код на незнакомом мне языке, поспособствовал моему размышлению о сути. Наоборот, если бы это было оформленно в виде java классов, я бы понял это гораздо быстрее, несмотря на то, что кода вроде как больше.
Во многих западных вузах основам программирования учат на Scheme/Racket/ML. И только потом дают Java.
1
Модератор
Эксперт функциональных языков программирования
3134 / 2281 / 469
Регистрация: 26.03.2015
Сообщений: 8,877
17.04.2020, 16:59
Лучший ответ Сообщение было отмечено Artmal как решение

Решение

Цитата Сообщение от Artmal Посмотреть сообщение
Детали должны зависеть от абстракций
В терминах ООП "детали" - это конкретные классы, а "абстракции" - это интерфейсы. То есть, применительно к ООП этот принцип будет звучать так:
Конкретные классы должны зависеть от интерфейсов и не должны зависеть от других конкретных классов.
(Разумеется, имеются ввиду конкретные классы, решающие разные, несвязанные задачи).

Это универсальный принцип, который применяется не только к классам в ООП.

Например, Ваша программа использует некую библиотеку для логирования. Она не должна зависеть от выбранной библиотеки. То есть, в коде не должны встречаться строки вида "var logger = new SomeLogger();". В Вашем проекте вообще не должно быть ссылки на эту библиотеку (длл, модуль и т.п.) . Это правило, очевидно, не распространяется на "конфигурационный" код, но весь такой код (если он есть) должен быть собран в одном месте.
1
88 / 86 / 55
Регистрация: 14.11.2015
Сообщений: 1,099
18.04.2020, 13:14  [ТС]
Резюмируя топик:

High level modules should not depend on low level modules; both should depend on abstractions. Abstractions should not depend on details. Details should depend upon abstractions.
Все о чем здесь говорится, это то, что зависимости какой-либо сущности следует объявлять абстрактными, а не конкретными имлементациями. Это касается полей класса, параметров конструкторов/методов, параметров методов интерфейсов или абстрактных классов. Естественно, нужно использовать это разумно и помнить про YAGNI.

Всем спасибо.
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
BasicMan
Эксперт
29316 / 5623 / 2384
Регистрация: 17.02.2009
Сообщений: 30,364
Блог
18.04.2020, 13:14
Помогаю со студенческими работами здесь

ASP.NET MVC - Inversion of Control
Привет всем энтузиастам ASP.NET MVC! Хотел бы задать вопрос - кто какой IoC контейнер юзает и какие фичи продукта определили выбор. ...

В поисках совершенных абстракций
Для C++ существует огромное множество библиотек выполненных в различных техниках исполнения. Программисты создавшие их следовали разным...

Посоветуйте литературу по выполнению прямоугольной изометрии детали, эскиза детали
посоветуйте литературу по выполнению прямоугольной изометрии детали,эскиза детали

В поле данные не должны превышать значения другого поля и должны быть не менее 0
У меня в задаче магазин и нужно добавить в таблицу поле с кол-вом товара на складе. Условие: кол-во товара не должно превышать кол-во...

Найти вероятность отказа узла
Узел содержит 2 независимо работающих детали. Вероятности отказа детали соответственно равны 0,05 и 0,08. Найти вероятность отказа узла,...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
8
Ответ Создать тему
Новые блоги и статьи
Инструменты COM: Сохранение данный из VARIANT в файл и загрузка из файла в VARIANT
bedvit 28.01.2026
Сохранение базовых типов COM и массивов (одномерных или двухмерных) любой вложенности (деревья) в файл, с возможностью выбора алгоритмов сжатия и шифрования. Часть библиотеки BedvitCOM Использованы. . .
Загрузка PNG с альфа-каналом на SDL3 для Android: с помощью SDL_LoadPNG (без SDL3_image)
8Observer8 28.01.2026
Содержание блога SDL3 имеет собственные средства для загрузки и отображения PNG-файлов с альфа-каналом и базовой работы с ними. В этой инструкции используется функция SDL_LoadPNG(), которая. . .
Загрузка PNG с альфа-каналом на SDL3 для Android: с помощью SDL3_image
8Observer8 27.01.2026
Содержание блога SDL3_image - это библиотека для загрузки и работы с изображениями. Эта пошаговая инструкция покажет, как загрузить и вывести на экран смартфона картинку с альфа-каналом, то есть с. . .
влияние грибов на сукцессию
anaschu 26.01.2026
Бифуркационные изменения массы гриба происходят тогда, когда мы уменьшаем массу компоста в 10 раз, а скорость прироста биомассы уменьшаем в три раза. Скорость прироста биомассы может уменьшаться за. . .
Воспроизведение звукового файла с помощью SDL3_mixer при касании экрана Android
8Observer8 26.01.2026
Содержание блога SDL3_mixer - это библиотека я для воспроизведения аудио. В отличие от инструкции по добавлению текста код по проигрыванию звука уже содержится в шаблоне примера. Нужно только. . .
Установка Android SDK, NDK, JDK, CMake и т.д.
8Observer8 25.01.2026
Содержание блога Перейдите по ссылке: https:/ / developer. android. com/ studio и в самом низу страницы кликните по архиву "commandlinetools-win-xxxxxx_latest. zip" Извлеките архив и вы увидите. . .
Вывод текста со шрифтом TTF на Android с помощью библиотеки SDL3_ttf
8Observer8 25.01.2026
Содержание блога Если у вас не установлены Android SDK, NDK, JDK, и т. д. то сделайте это по следующей инструкции: Установка Android SDK, NDK, JDK, CMake и т. д. Сборка примера Скачайте. . .
Использование SDL3-callbacks вместо функции main() на Android, Desktop и WebAssembly
8Observer8 24.01.2026
Содержание блога Если вы откроете примеры для начинающих на официальном репозитории SDL3 в папке: examples, то вы увидите, что все примеры используют следующие четыре обязательные функции, а. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru