Это вторая часть статьи. Первую часть читайте здесь.
Поведенческие паттерны
13. Chain of Responsibility (Цепочка обязанностей)
Описание: Позволяет передавать запросы последовательно по цепочке обработчиков.
Когда использовать: Когда есть более одного объекта, который может обработать запрос.
Пример кода:
abstract class Handler(private val next: Handler?) { open fun handle(request: String) { next?.handle(request) } } class AuthenticationHandler(next: Handler?) : Handler(next) { override fun handle(request: String) { if (request.contains("auth")) { println("Аутентификация прошла") super.handle(request) } else { println("Аутентификация не удалась") } } } class LoggingHandler(next: Handler?) : Handler(next) { override fun handle(request: String) { println("Логирование запроса: $request") super.handle(request) } } fun main() { val handler = AuthenticationHandler(LoggingHandler(null)) handler.handle("auth: запрос к ресурсу") }
14. Command (Команда)
Описание: Инкапсулирует запрос как объект, позволяя параметризовать клиентов с разными запросами.
Когда использовать: Когда нужно параметризовать объекты выполняемым действием.
Пример кода:
interface Command { fun execute() } class Light { fun turnOn() = println("Свет включен") fun turnOff() = println("Свет выключен") } class TurnOnCommand(private val light: Light) : Command { override fun execute() = light.turnOn() } class TurnOffCommand(private val light: Light) : Command { override fun execute() = light.turnOff() } class RemoteControl { private val commands = mutableListOf<Command>() fun addCommand(command: Command) = commands.add(command) fun executeCommands() = commands.forEach { it.execute() } } fun main() { val light = Light() val turnOn = TurnOnCommand(light) val turnOff = TurnOffCommand(light) val remote = RemoteControl() remote.addCommand(turnOn) remote.addCommand(turnOff) remote.executeCommands() }
15. Iterator (Итератор)
Описание: Предоставляет способ последовательного доступа к элементам агрегатного объекта без раскрытия его внутреннего представления.
Когда использовать: Когда нужно предоставить единый интерфейс для обхода различных коллекций.
Пример кода:
class Notification(val message: String) class NotificationCollection { private val notifications = mutableListOf<Notification>() fun addNotification(notification: Notification) = notifications.add(notification) fun iterator(): Iterator<Notification> = notifications.iterator() } fun main() { val collection = NotificationCollection() collection.addNotification(Notification("Уведомление 1")) collection.addNotification(Notification("Уведомление 2")) collection.addNotification(Notification("Уведомление 3")) val iterator = collection.iterator() while (iterator.hasNext()) { val notification = iterator.next() println(notification.message) } }
16. Mediator (Посредник)
Описание: Определяет объект, который инкапсулирует способ взаимодействия множества объектов.
Когда использовать: Когда нужно упростить коммуникацию между множеством взаимодействующих объектов.
Пример кода:
interface Mediator { fun notify(sender: Component, event: String) } abstract class Component(protected val mediator: Mediator) class Button(mediator: Mediator) : Component(mediator) { fun click() { println("Кнопка нажата") mediator.notify(this, "click") } } class TextBox(mediator: Mediator) : Component(mediator) { fun setText(text: String) = println("Текстовое поле установлено в '$text'") } class AuthenticationDialog : Mediator { private val button = Button(this) private val textBox = TextBox(this) fun simulateUserAction() = button.click() override fun notify(sender: Component, event: String) { if (sender is Button && event = "click") { textBox.setText("Авторизация пользователя") } } } fun main() { val dialog = AuthenticationDialog() dialog.simulateUserAction() }
17. Memento (Хранитель)
Описание: Сохраняет внутреннее состояние объекта без нарушения инкапсуляции для возможности восстановления.
Когда использовать: Когда нужно сохранять и восстанавливать прошлые состояния объекта.
Пример кода:
class Editor { var content: String = "" fun save(): Memento = Memento(content) fun restore(memento: Memento) { content = memento.content } data class Memento(val content: String) } class History { private val states = mutableListOf<Editor.Memento>() fun push(memento: Editor.Memento) = states.add(memento) fun pop(): Editor.Memento = states.removeAt(states.lastIndex) } fun main() { val editor = Editor() val history = History() editor.content = "Состояние 1" history.push(editor.save()) editor.content = "Состояние 2" history.push(editor.save()) editor.content = "Состояние 3" editor.restore(history.pop()) println("Текущее содержание: ${editor.content}") editor.restore(history.pop()) println("Текущее содержание: ${editor.content}") }
18. Observer (Наблюдатель)
Описание: Определяет зависимость «один ко многим» между объектами так, что при изменении состояния одного объекта все зависящие от него оповещаются.
Когда использовать: Когда изменение состояния одного объекта требует изменения других объектов.
Пример кода:
interface Observer { fun update(state: Int) } class Subject { private val observers = mutableListOf<Observer>() var state: Int = 0 set(value) { field = value notifyAllObservers() } fun attach(observer: Observer) = observers.add(observer) private fun notifyAllObservers() = observers.forEach { it.update(state) } } class BinaryObserver : Observer { override fun update(state: Int) = println("Двоичное представление: ${Integer.toBinaryString(state)}") } class HexObserver : Observer { override fun update(state: Int) = println("Шестнадцатеричное представление: ${Integer.toHexString(state)}") } fun main() { val subject = Subject() subject.attach(BinaryObserver()) subject.attach(HexObserver()) subject.state = 15 subject.state = 10 }
19. State (Состояние)
Описание: Позволяет объекту менять свое поведение при изменении внутреннего состояния.
Когда использовать: Когда поведение объекта зависит от его состояния.
Пример кода:
interface State { fun handle(context: Context) } class Context { var state: State = ConcreteStateA() fun request() = state.handle(this) } class ConcreteStateA : State { override fun handle(context: Context) { println("Состояние А, переходим к В") context.state = ConcreteStateB() } } class ConcreteStateB : State { override fun handle(context: Context) { println("Состояние В, переходим к А") context.state = ConcreteStateA() } } fun main() { val context = Context() context.request() context.request() context.request() }
20. Strategy (Стратегия)
Описание: Определяет семейство алгоритмов, инкапсулирует каждый из них и обеспечивает их взаимозаменяемость.
Когда использовать: Когда есть несколько похожих алгоритмов, и нужно переключаться между ними во время выполнения.
Пример кода:
interface Strategy { fun execute(a: Int, b: Int): Int } class AdditionStrategy : Strategy { override fun execute(a: Int, b: Int): Int = a + b } class SubtractionStrategy : Strategy { override fun execute(a: Int, b: Int): Int = a - b } class Context(private var strategy: Strategy) { fun setStrategy(strategy: Strategy) { this.strategy = strategy } fun executeStrategy(a: Int, b: Int): Int = strategy.execute(a, b) } fun main() { val context = Context(AdditionStrategy()) println("10 + 5 = ${context.executeStrategy(10, 5)}") context.setStrategy(SubtractionStrategy()) println("10 - 5 = ${context.executeStrategy(10, 5)}") }
21. Template Method (Шаблонный метод)
Описание: Определяет скелет алгоритма в методе, оставляя реализацию шагов подклассам.
Когда использовать: Когда нужно определить основной алгоритм и делегировать реализацию отдельных шагов подклассам.
Пример кода:
abstract class Game { fun play() { initialize() startPlay() endPlay() } abstract fun initialize() abstract fun startPlay() abstract fun endPlay() } class Football : Game() { override fun initialize() = println("Футбол: Игра инициализирована") override fun startPlay() = println("Футбол: Игра начата") override fun endPlay() = println("Футбол: Игра завершена") } class Basketball : Game() { override fun initialize() = println("Баскетбол: Игра инициализирована") override fun startPlay() = println("Баскетбол: Игра начата") override fun endPlay() = println("Баскетбол: Игра завершена") } fun main() { val game1: Game = Football() game1.play() val game2: Game = Basketball() game2.play() }
22. Visitor (Посетитель)
Описание: Разделяет алгоритмы от структур данных, по которым они работают.
Когда использовать: Когда у вас есть сложная структура объектов, и вы хотите выполнять над ними разнообразные операции, не изменяя классы этих объектов.
Пример кода:
// Элемент, который принимает посетителя interface Shape { fun accept(visitor: Visitor) } // Конкретные элементы class Circle(val radius: Double) : Shape { override fun accept(visitor: Visitor) { visitor.visitCircle(this) } } class Rectangle(val width: Double, val height: Double) : Shape { override fun accept(visitor: Visitor) { visitor.visitRectangle(this) } } // Интерфейс посетителя interface Visitor { fun visitCircle(circle: Circle) fun visitRectangle(rectangle: Rectangle) } // Посетитель для рисования фигур class DrawVisitor : Visitor { override fun visitCircle(circle: Circle) { println("Рисуем круг с радиусом ${circle.radius}") } override fun visitRectangle(rectangle: Rectangle) { println("Рисуем прямоугольник шириной ${rectangle.width} и высотой ${rectangle.height}") } } // Посетитель для вычисления площади class AreaVisitor : Visitor { override fun visitCircle(circle: Circle) { val area = Math.PI * circle.radius * circle.radius println("Площадь круга: $area") } override fun visitRectangle(rectangle: Rectangle) { val area = rectangle.width * rectangle.height println("Площадь прямоугольника: $area") } } fun main() { val shapes = listOf<Shape>( Circle(5.0), Rectangle(3.0, 4.0) ) val drawVisitor = DrawVisitor() val areaVisitor = AreaVisitor() // Рисуем фигуры println("=== Рисование фигур ===") shapes.forEach { it.accept(drawVisitor) } // Вычисляем площади фигур println("\n=== Вычисление площади фигур ===") shapes.forEach { it.accept(areaVisitor) } }
Это основные паттерны проектирования с примерами на языке Kotlin. Каждый паттерн решает определенную проблему и может быть использован в различных ситуациях для улучшения архитектуры приложения.
ссылка на оригинал статьи https://habr.com/ru/articles/860030/
Добавить комментарий