diff --git a/Head-First-Design-Patterns-master.zip b/Head-First-Design-Patterns-master.zip new file mode 100644 index 0000000..079fd3b Binary files /dev/null and b/Head-First-Design-Patterns-master.zip differ diff --git a/README.md b/README.md index 2ad529a..e915124 100644 --- a/README.md +++ b/README.md @@ -1,12 +1,18 @@ # Паттерны проектирования на языке D -Паттерны проектирования по книге [Head First. Паттерны проектирования](https://ftp.zhirov.kz/books/IT/%D0%9F%D0%B0%D1%82%D1%82%D0%B5%D1%80%D0%BD%D1%8B/Head%20First.%20%D0%9F%D0%B0%D1%82%D1%82%D0%B5%D1%80%D0%BD%D1%8B%20%D0%BF%D1%80%D0%BE%D0%B5%D0%BA%D1%82%D0%B8%D1%80%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D1%8F%20%28%D0%AD%D1%80%D0%B8%D0%BA%20%D0%A4%D1%80%D0%B8%D0%BC%D0%B5%D0%BD%2C%20%D0%AD%D0%BB%D0%B8%D0%B7%D0%B0%D0%B1%D0%B5%D1%82%20%D0%A0%D0%BE%D0%B1%D1%81%D0%BE%D0%BD%29%202022.pdf) +Паттерны проектирования по книге [Head First. Паттерны проектирования](https://ftp.zhirov.kz/books/IT/%D0%9F%D0%B0%D1%82%D1%82%D0%B5%D1%80%D0%BD%D1%8B/Head%20First.%20%D0%9F%D0%B0%D1%82%D1%82%D0%B5%D1%80%D0%BD%D1%8B%20%D0%BF%D1%80%D0%BE%D0%B5%D0%BA%D1%82%D0%B8%D1%80%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D1%8F%20%28%D0%AD%D1%80%D0%B8%D0%BA%20%D0%A4%D1%80%D0%B8%D0%BC%D0%B5%D0%BD%2C%20%D0%AD%D0%BB%D0%B8%D0%B7%D0%B0%D0%B1%D0%B5%D1%82%20%D0%A0%D0%BE%D0%B1%D1%81%D0%BE%D0%BD%29%202022.pdf) ([исходный код на Java](Head-First-Design-Patterns-master.zip)) ## Паттерны +### Поведенческие + 1. [Стратегия](strategy/) 2. [Наблюдатель](observer/) +### Структурные + +1. [Декоратор](decorator/) + ## Компиляция ```sh diff --git a/decorator/README.md b/decorator/README.md new file mode 100644 index 0000000..7cd41a0 --- /dev/null +++ b/decorator/README.md @@ -0,0 +1,9 @@ +# Декоратор + +Декоратор — это структурный паттерн проектирования, который позволяет динамически добавлять объектам новую функциональность, оборачивая их в полезные «обёртки». + +Типы декораторов соответствуют типам декорируемых компонентов (соответствие достигается посредством наследования или реализации интерфейса). Декораторы изменяют поведение компонентов, добавляя новую функциональность до и (или) после (или даже вместо) вызовов методов компонентов. Компонент может декорироваться любым количеством декораторов. Декораторы обычно прозрачны для клиентов компонента (если клиентский код не зависит от конкретного типа компонента). + +## Принцип + +- Согласно принципу открытости/закрытости системы должны проектироваться так, чтобы их закрытые компоненты были изолированы от новых расширений diff --git a/observer/README.md b/observer/README.md index 29c8b86..aecc853 100644 --- a/observer/README.md +++ b/observer/README.md @@ -2,7 +2,7 @@ Наблюдатель — это поведенческий паттерн проектирования, который создаёт механизм подписки, позволяющий одним объектам следить и реагировать на события, происходящие в других объектах. -При использовании паттерна возможен как запрос, так и активная доставка данных от субъекта (запрос считается более "правильным"). +При использовании паттерна возможен как [запрос](request/), так и [активная доставка](delivery/) данных от субъекта (запрос считается более "правильным"). - **Активная доставка** - передача субъектом аргументов в качестве параметров функции `update()` - **Запрос** - подразумевает получение необходимых параметров от субъекта внутри функции `update()` diff --git a/observer/delivery/app.d b/observer/delivery/app.d new file mode 100644 index 0000000..018c95a --- /dev/null +++ b/observer/delivery/app.d @@ -0,0 +1,22 @@ +module observer.delivery.app; + +import observer.delivery.weatherdata; +import observer.delivery.currentconditionsdisplay; +import observer.delivery.heatindexdisplay; +import observer.delivery.forecastdisplay; +import observer.delivery.statiscticdisplay; + +void main() +{ + WeatherData weatherData = new WeatherData(); + CurrentConditionsDisplay currentDisplay = new CurrentConditionsDisplay(weatherData); + HeatIndexDisplay heatIndexDisplay = new HeatIndexDisplay(weatherData); + ForecastDisplay forecastDisplay = new ForecastDisplay(weatherData); + StatisticsDisplay statisticsDisplay = new StatisticsDisplay(weatherData); + + weatherData.setMeasurements(80, 65, 30.4f); + weatherData.setMeasurements(82, 70, 29.2f); + weatherData.removeObserver(forecastDisplay); + weatherData.setMeasurements(78, 90, 29.2f); + weatherData.setMeasurements(81, 72, 29.5f); +} diff --git a/observer/delivery/currentconditionsdisplay.d b/observer/delivery/currentconditionsdisplay.d new file mode 100644 index 0000000..c020b26 --- /dev/null +++ b/observer/delivery/currentconditionsdisplay.d @@ -0,0 +1,31 @@ +module observer.delivery.currentconditionsdisplay; + +import observer.delivery.displayelement; +import observer.delivery.observer; +import observer.delivery.weatherdata; +import std.stdio : writeln; +import std.format : format; + +class CurrentConditionsDisplay : Observer, DisplayElement +{ +private: + float temperature; + float humidity; +public: + this(WeatherData weatherData) + { + weatherData.registerObserver(this); + } + + override void update(float temperature, float humidity, float pressure) + { + this.temperature = temperature; + this.humidity = humidity; + display(); + } + + override void display() + { + writeln("Current conditions: %3.1f".format(temperature), "F degrees and %3.1f%% humidity".format(humidity)); + } +} diff --git a/observer/delivery/displayelement.d b/observer/delivery/displayelement.d new file mode 100644 index 0000000..7fb8b5b --- /dev/null +++ b/observer/delivery/displayelement.d @@ -0,0 +1,6 @@ +module observer.delivery.displayelement; + +interface DisplayElement +{ + void display(); +} diff --git a/observer/delivery/forecastdisplay.d b/observer/delivery/forecastdisplay.d new file mode 100644 index 0000000..c227136 --- /dev/null +++ b/observer/delivery/forecastdisplay.d @@ -0,0 +1,38 @@ +module observer.delivery.forecastdisplay; + +import observer.delivery.displayelement; +import observer.delivery.observer; +import observer.delivery.weatherdata; +import std.stdio : write, writeln; +import std.format : format; + +class ForecastDisplay : Observer, DisplayElement +{ +private: + float currentPressure = 29.92f; + float lastPressure; +public: + this(WeatherData weatherData) + { + weatherData.registerObserver(this); + } + + override void update(float temperature, float humidity, float pressure) + { + lastPressure = currentPressure; + currentPressure = pressure; + display(); + } + + override void display() + { + write("Forecast: "); + if (currentPressure > lastPressure) { + writeln("Improving weather on the way!"); + } else if (currentPressure == lastPressure) { + writeln("More of the same"); + } else if (currentPressure < lastPressure) { + writeln("Watch out for cooler, rainy weather"); + } + } +} diff --git a/observer/delivery/heatindexdisplay.d b/observer/delivery/heatindexdisplay.d new file mode 100644 index 0000000..38e0329 --- /dev/null +++ b/observer/delivery/heatindexdisplay.d @@ -0,0 +1,38 @@ +module observer.delivery.heatindexdisplay; + +import observer.delivery.displayelement; +import observer.delivery.observer; +import observer.delivery.weatherdata; +import std.stdio : writeln; + +class HeatIndexDisplay : Observer, DisplayElement +{ +private: + float heatIndex; + + float computeHeatIndex(float t, float rh) + { + return ((16.923 + (0.185212 * t) + (5.37941 * rh) - (0.100254 * t * rh) + (0.00941695 * (t * t)) + + (0.00728898 * (rh * rh)) + (0.000345372 * (t * t * rh)) - (0.000814971 * (t * rh * rh)) + + (0.0000102102 * (t * t * rh * rh)) - (0.000038646 * (t * t * t)) + (0.0000291583 * (rh * rh * rh)) + + (0.00000142721 * (t * t * t * rh)) + (0.000000197483 * (t * rh * rh * rh)) + - (0.0000000218429 * (t * t * t * rh * rh)) + 0.000000000843296 * (t * t * rh * rh * rh)) + - (0.0000000000481975 * (t * t * t * rh * rh * rh))); + } +public: + this(WeatherData weatherData) + { + weatherData.registerObserver(this); + } + + override void update(float temperature, float humidity, float pressure) + { + this.heatIndex = computeHeatIndex(temperature, humidity); + display(); + } + + override void display() + { + writeln("Heat index is ", heatIndex); + } +} \ No newline at end of file diff --git a/observer/delivery/observer.d b/observer/delivery/observer.d new file mode 100644 index 0000000..99edfcb --- /dev/null +++ b/observer/delivery/observer.d @@ -0,0 +1,6 @@ +module observer.delivery.observer; + +interface Observer +{ + void update(float temperature, float humidity, float pressure); +} diff --git a/observer/delivery/statiscticdisplay.d b/observer/delivery/statiscticdisplay.d new file mode 100644 index 0000000..a050cd7 --- /dev/null +++ b/observer/delivery/statiscticdisplay.d @@ -0,0 +1,45 @@ +module observer.delivery.statiscticdisplay; + +import observer.delivery.displayelement; +import observer.delivery.observer; +import observer.delivery.weatherdata; +import std.stdio : writeln; +import std.format : format; + +class StatisticsDisplay : Observer, DisplayElement +{ +private: + float maxTemp = 0.0f; + float minTemp = 200; + float tempSum= 0.0f; + int numReadings; +public: + this(WeatherData weatherData) + { + weatherData.registerObserver(this); + } + + override void update(float temperature, float humidity, float pressure) + { + tempSum += temperature; + numReadings++; + + if (temperature > maxTemp) + { + maxTemp = temperature; + } + + if (temperature < minTemp) + { + minTemp = temperature; + } + + display(); + } + + override void display() + { + writeln("Avg/Max/Min temperature = ", (tempSum / numReadings), '/', maxTemp, '/', minTemp); + // writeln("Avg/Max/Min temperature = ".format(temperature), "F degrees and %3.1f%% humidity".format(humidity)); + } +} diff --git a/observer/delivery/subject.d b/observer/delivery/subject.d new file mode 100644 index 0000000..ee48d6f --- /dev/null +++ b/observer/delivery/subject.d @@ -0,0 +1,10 @@ +module observer.delivery.subject; + +import observer.delivery.observer; + +interface Subject +{ + void registerObserver(Observer o); + void removeObserver(Observer o); + void notifyObservers(); +} diff --git a/observer/delivery/weatherdata.d b/observer/delivery/weatherdata.d new file mode 100644 index 0000000..0cd8d32 --- /dev/null +++ b/observer/delivery/weatherdata.d @@ -0,0 +1,60 @@ +module observer.delivery.weatherdata; + +import observer.delivery.subject; +import observer.delivery.observer; +import std.algorithm : remove, countUntil; + +class WeatherData : Subject +{ +private: + Observer[] observers; + float temperature, humidity, pressure; +public: + override void registerObserver(Observer o) + { + observers ~= o; + } + + override void removeObserver(Observer o) + { + // Вызовет ошибку в случае отсутствия элемента в массиве после его поиска + // observers = observers.remove(observers.countUntil(o)); + observers = remove!(current => current == o)(observers); + } + + override void notifyObservers() + { + foreach (Observer o; observers) + { + o.update(temperature, humidity, pressure); + } + } + + void measurementsChanged() + { + notifyObservers(); + } + + void setMeasurements(float temperature, float humidity, float pressure) + { + this.temperature = temperature; + this.humidity = humidity; + this.pressure = pressure; + measurementsChanged(); + } + + @property float getTemperature() + { + return temperature; + } + + @property float getHumidity() + { + return humidity; + } + + @property float getPressure() + { + return pressure; + } +} diff --git a/observer/app.d b/observer/request/app.d similarity index 72% rename from observer/app.d rename to observer/request/app.d index 3db78f5..ce04693 100644 --- a/observer/app.d +++ b/observer/request/app.d @@ -1,10 +1,10 @@ -module observer.app; +module observer.request.app; -import observer.weatherdata; -import observer.currentconditionsdisplay; -import observer.heatindexdisplay; -import observer.forecastdisplay; -import observer.statiscticdisplay; +import observer.request.weatherdata; +import observer.request.currentconditionsdisplay; +import observer.request.heatindexdisplay; +import observer.request.forecastdisplay; +import observer.request.statiscticdisplay; void main() { diff --git a/observer/currentconditionsdisplay.d b/observer/request/currentconditionsdisplay.d similarity index 80% rename from observer/currentconditionsdisplay.d rename to observer/request/currentconditionsdisplay.d index aaec318..020099e 100644 --- a/observer/currentconditionsdisplay.d +++ b/observer/request/currentconditionsdisplay.d @@ -1,8 +1,8 @@ -module observer.currentconditionsdisplay; +module observer.request.currentconditionsdisplay; -import observer.displayelement; -import observer.observer; -import observer.weatherdata; +import observer.request.displayelement; +import observer.request.observer; +import observer.request.weatherdata; import std.stdio : writeln; import std.format : format; diff --git a/observer/displayelement.d b/observer/request/displayelement.d similarity index 55% rename from observer/displayelement.d rename to observer/request/displayelement.d index 5154dfc..f1b637e 100644 --- a/observer/displayelement.d +++ b/observer/request/displayelement.d @@ -1,4 +1,4 @@ -module observer.displayelement; +module observer.request.displayelement; interface DisplayElement { diff --git a/observer/forecastdisplay.d b/observer/request/forecastdisplay.d similarity index 84% rename from observer/forecastdisplay.d rename to observer/request/forecastdisplay.d index 9840471..5b07f23 100644 --- a/observer/forecastdisplay.d +++ b/observer/request/forecastdisplay.d @@ -1,8 +1,8 @@ -module observer.forecastdisplay; +module observer.request.forecastdisplay; -import observer.displayelement; -import observer.observer; -import observer.weatherdata; +import observer.request.displayelement; +import observer.request.observer; +import observer.request.weatherdata; import std.stdio : write, writeln; import std.format : format; diff --git a/observer/heatindexdisplay.d b/observer/request/heatindexdisplay.d similarity index 88% rename from observer/heatindexdisplay.d rename to observer/request/heatindexdisplay.d index ac98ee8..7fb84e1 100644 --- a/observer/heatindexdisplay.d +++ b/observer/request/heatindexdisplay.d @@ -1,8 +1,8 @@ -module observer.heatindexdisplay; +module observer.request.heatindexdisplay; -import observer.displayelement; -import observer.observer; -import observer.weatherdata; +import observer.request.displayelement; +import observer.request.observer; +import observer.request.weatherdata; import std.stdio : writeln; class HeatIndexDisplay : Observer, DisplayElement diff --git a/observer/observer.d b/observer/request/observer.d similarity index 55% rename from observer/observer.d rename to observer/request/observer.d index 8665f4d..0b69040 100644 --- a/observer/observer.d +++ b/observer/request/observer.d @@ -1,4 +1,4 @@ -module observer.observer; +module observer.request.observer; interface Observer { diff --git a/observer/statiscticdisplay.d b/observer/request/statiscticdisplay.d similarity index 86% rename from observer/statiscticdisplay.d rename to observer/request/statiscticdisplay.d index 55e7601..292a698 100644 --- a/observer/statiscticdisplay.d +++ b/observer/request/statiscticdisplay.d @@ -1,8 +1,8 @@ -module observer.statiscticdisplay; +module observer.request.statiscticdisplay; -import observer.displayelement; -import observer.observer; -import observer.weatherdata; +import observer.request.displayelement; +import observer.request.observer; +import observer.request.weatherdata; import std.stdio : writeln; import std.format : format; diff --git a/observer/subject.d b/observer/request/subject.d similarity index 65% rename from observer/subject.d rename to observer/request/subject.d index 8fa85b1..822e06e 100644 --- a/observer/subject.d +++ b/observer/request/subject.d @@ -1,6 +1,6 @@ -module observer.subject; +module observer.request.subject; -import observer.observer; +import observer.request.observer; interface Subject { diff --git a/observer/weatherdata.d b/observer/request/weatherdata.d similarity index 92% rename from observer/weatherdata.d rename to observer/request/weatherdata.d index 9970d1b..32007fa 100644 --- a/observer/weatherdata.d +++ b/observer/request/weatherdata.d @@ -1,7 +1,7 @@ -module observer.weatherdata; +module observer.request.weatherdata; -import observer.subject; -import observer.observer; +import observer.request.subject; +import observer.request.observer; import std.algorithm : remove, countUntil; class WeatherData : Subject diff --git a/strategy/README.md b/strategy/README.md index ff9ded8..4abfbda 100644 --- a/strategy/README.md +++ b/strategy/README.md @@ -2,8 +2,7 @@ Инкапсуляция алгоритма в объект — это назначение паттерна **стратегия**. -Поведенческий паттерн проектирования, который определяет семейство схожих алгоритмов и -помещает каждый из них в собственный класс, после чего алгоритмы можно взаимозаменять прямо во время исполнения программы. +Поведенческий паттерн проектирования, который определяет семейство схожих алгоритмов и помещает каждый из них в собственный класс, после чего алгоритмы можно взаимозаменять прямо во время исполнения программы. ## Код diff --git a/strategy/duck.d b/strategy/duck.d index 60e963e..76a0398 100644 --- a/strategy/duck.d +++ b/strategy/duck.d @@ -1,4 +1,5 @@ module strategy.duck; + import strategy.flybehavior; import strategy.quackbehavior; import std.stdio : writeln;