** Table of Contents ** Is it this pattern that makes it possible to flexibly determine the object to be processed between the parent and child in the object that has a parent-child relationship?
Avoid combining objects that send and receive requests by giving one or more objects the opportunity to process the request. It connects multiple objects to be received in a chain, and passes the request along the chain until an object processes the request.
-Handler Abstract class of parent and child class -ConcreteHandler Handler's concrete class ・ Client user
If you compare the parts that make up the screen, I think they have the following parent-child relationship.
window
----Dialog to be displayed in the window
--------Buttons in the dialog
----Button in the window
Implement sample code that allows you to freely decide which object to handle when a problem occurs by manipulating any of the objects.
Common class A superclass of all objects. If the messageType is set to something other than Normal when the View is instantiated, the processing for the defect will be executed in the object. The View for which Normal is set leaves the processing to the parent View. And the parent View ... repeats
View.kt
package chainofresponsibility
abstract class View(private val parent: View?, private val messageType: MessageType) {
enum class MessageType {
Normal,
Warning,
Danger
}
protected fun handleHelp() {
if (hasMessage()) {
helpLogic()
} else {
parent?.handleHelp()
}
}
abstract fun helpLogic()
private fun hasMessage(): Boolean {
val ret = MessageType.Normal != messageType
if (ret) {
createDialog()
}
return ret
}
private fun createDialog() {
when (messageType) {
MessageType.Warning -> {
print("Warning dialog:")
}
MessageType.Danger -> {
print("Error dialog:")
}
}
}
}
Window
Window.kt
package chainofresponsibility
class Window(parent: View?, messageType: View.MessageType): View(parent, messageType) {
override fun helpLogic() {
println("Problems caused by windows!")
}
}
dialog
Dialog.kt
package chainofresponsibility
class Dialog(parent: View?, messageType: View.MessageType): View(parent, messageType) {
override fun helpLogic() {
println("Problems caused by dialogs!")
}
}
button If you pass a non-zero value to the action method, a problem will occur.
Button.kt
package chainofresponsibility
class Button(parent: View?, messageType: View.MessageType): View(parent, messageType) {
fun action(arg: Int) {
if (arg == 0) {
println("Successful completion")
} else {
handleHelp()
}
}
override fun helpLogic() {
println("Problems caused by buttons!")
}
}
A problem occurs in action (1). In the sample code below, the window catches the bug that occurred in button1, and the dialog catches the bug that occurred in button2. If you change the message type of dialog to Normal, window will catch it.
Client.kt
package chainofresponsibility
class Client {
init {
//Window
val window = Window(null, View.MessageType.Danger)
//Buttons located directly below the window
val button1 = Button(window, View.MessageType.Normal)
//Dialog placed directly under the window
val dialog = Dialog(window, View.MessageType.Warning)
//Buttons placed in the dialog
val button2 = Button(dialog, View.MessageType.Normal)
button1.action(0)
button1.action(1)
button1.action(0)
button2.action(0)
button2.action(1)
button2.action(0)
}
}
[out-put]
Successful completion
Error dialog: Bug caused by window!
Successful completion
Successful completion
Warning dialog: Problems caused by the dialog!
Successful completion
How about this pattern ...
At first glance, it seems that it becomes impossible to manage which parent object handles it and eventually creates a bug, but in the first place it is a pattern that makes it unnecessary to know the object that receives the message, so is that okay? .. Hmm.
Recommended Posts