MrOzOn пре 4 година
родитељ
комит
a2a08f925e

+ 32 - 0
src/behavioral_pattern/README.MD

@@ -20,3 +20,35 @@
 - _получение не гарантировано_. Поскольку у запроса нет явного получателя, то нет и гарантий, что он вообще будет обработан: он может достичь конца цепочки и пропасть.
 
 
+# [Команда (Command)](./command/main.kt)
+
+Это поведенческий паттерн проектирования, который превращает запросы в объекты, позволяя передавать их как аргументы при вызове методов, ставить запросы в очередь, логировать их, а также поддерживать отмену операций.
+
+## Другое название
+Действие (Action), Транзакция (Transaction)
+
+
+## Применимость
+
+- параметризация объектов выполняемым действием
+- определение, постановка в очередь и выполнение запросов в разное время
+- поддержка отмены операций
+- поддержка протоколирования изменений, чтобы их можно было выполнить повторно после сбоя в системе
+- структурирование системы на основе высокоуровневых операций, построенных из примитивных
+
+## Отношения
+
+- клиент создает объект конкретной команды и устанавливает для него получателя
+- инициатор сохраняет объект конкретной команды
+- инициатор отправляет запрос, вызывая операцию команды Execute. Если поддерживается отмена выполненных действий, то перед вызовом Execute сохраняет информацию о состоянии, достаточную для выполнения отмены
+- объект конкретной команды вызывает операции получателя для выполнения запроса
+
+## Результаты
+
+- команда отделяет объект, инициирующий операцию, от объекта, располагающего информацией о том, как ее выполнить
+- команды — это самые настоящие объекты. Их можно обрабатывать и расширять точно так же, как любые другие объекты
+- из простых команд можно собирать составные
+- новые команды добавляются легко, поскольку никакие существующие классы изменять не нужно
+
+
+

+ 17 - 0
src/behavioral_pattern/command/Command.kt

@@ -0,0 +1,17 @@
+package behavioral_pattern.command
+
+abstract class Command(private val editor: Editor) {
+    private var backup: String? = null
+
+    fun backup(){
+        backup = editor.textField.text
+    }
+
+    fun undo(){
+        editor.textField.text = backup
+    }
+
+    override fun toString(): String = javaClass.canonicalName
+
+    abstract fun execute(): Boolean
+}

+ 15 - 0
src/behavioral_pattern/command/CommandHistory.kt

@@ -0,0 +1,15 @@
+package behavioral_pattern.command
+
+import java.util.*
+
+class CommandHistory{
+    private val history = Stack<Command>()
+
+    fun push(command: Command){
+        history.push(command)
+    }
+
+    fun pop():Command = history.pop()
+
+    val isEmpty: Boolean get() = history.isEmpty()
+}

+ 34 - 0
src/behavioral_pattern/command/ConcreteCommands.kt

@@ -0,0 +1,34 @@
+package behavioral_pattern.command
+
+class CopyCommand(private val editor: Editor): Command(editor){
+    override fun execute(): Boolean {
+        editor.clipboard = editor.textField.text
+        return false
+    }
+}
+
+class PastCommand(private val editor: Editor): Command(editor){
+    override fun execute(): Boolean {
+        if(editor.clipboard.isNullOrEmpty()) return false
+        backup()
+        editor.textField.insert(editor.clipboard, editor.textField.caretPosition)
+        return true
+    }
+}
+
+class CutCommand(private val editor: Editor): Command(editor){
+    override fun execute(): Boolean {
+        if(editor.textField.selectedText.isNullOrEmpty()) return false
+        backup()
+        val source = editor.textField.text
+        editor.clipboard = editor.textField.selectedText
+        editor.textField.text = cutString(source)
+        return true
+    }
+
+    private fun cutString(source: String): String {
+        val start = source.substring(0, editor.textField.selectionStart)
+        val end = source.substring(editor.textField.selectionEnd)
+        return start+end
+    }
+}

+ 58 - 0
src/behavioral_pattern/command/Editor.kt

@@ -0,0 +1,58 @@
+package behavioral_pattern.command
+
+import java.awt.FlowLayout
+import javax.swing.*
+
+class Editor {
+    val textField: JTextArea = JTextArea()
+    var clipboard: String? = null
+    private val history = CommandHistory()
+
+    init {
+        val frame = JFrame("Simple text editor")
+        val content = JPanel()
+        frame.contentPane = content
+        frame.defaultCloseOperation = WindowConstants.EXIT_ON_CLOSE
+        content.layout = BoxLayout(content, BoxLayout.Y_AXIS)
+        textField.lineWrap = true
+        content.add(textField)
+        val buttons = JPanel(FlowLayout(FlowLayout.CENTER))
+        val ctrlC = JButton("Ctrl+C")
+        val ctrlX = JButton("Ctrl+X")
+        val ctrlV = JButton("Ctrl+V")
+        val ctrlZ = JButton("Ctrl+Z")
+        ctrlC.addActionListener {
+            executeCommand(CopyCommand(this))
+        }
+        ctrlX.addActionListener {
+            executeCommand(CutCommand(this))
+        }
+        ctrlV.addActionListener {
+            executeCommand(PastCommand(this))
+        }
+        ctrlZ.addActionListener {
+            undo()
+        }
+        buttons.add(ctrlC)
+        buttons.add(ctrlX)
+        buttons.add(ctrlV)
+        buttons.add(ctrlZ)
+        content.add(buttons)
+        frame.setSize(450, 200);
+        frame.setLocationRelativeTo(null);
+        frame.isVisible = true;
+    }
+
+    private fun executeCommand(command: Command) {
+        if (command.execute()) {
+            println("push $command")
+            history.push(command)
+        }
+    }
+
+    private fun undo() {
+        if (history.isEmpty) return
+        val command = history.pop()
+        command.undo()
+    }
+}

+ 5 - 0
src/behavioral_pattern/command/main.kt

@@ -0,0 +1,5 @@
+package behavioral_pattern.command
+
+fun main(){
+    Editor()
+}