Adding decorators

Now we need to add the decorators to the window. To do this, we will create a WindowDecorator class, which is our decorator. This class implements the following Window component:

class WindowDecorator(private val window: Window) : Window {

override fun getDescription(): String {
return window.getDescription()
}

override fun getPrice(): Double {
return window.getPrice()
}
}

This class takes an instance of a Window type in its constructor, and this is the instance that is decorated. We also override the getDescription() and getPrice() functions.

Now let's write a concrete decorator. This is called Arched, which refers to the shape of the window:

class Arched(private val window: Window) : WindowDecorator(window) {
internal var description: String
internal var price: Double
init {

description = "Arched shape"
price = 15.00
}

override fun getDescription(): String {
var desc = super.getDescription()
return "$desc, $description"
}

override fun getPrice(): Double {
return super.getPrice() + price
}
}

This class extends from WindowDecorator, taking an object of the Window type that will be decorated. It then calls the parent class constructor. Note the syntax in Kotlin for this step. This is just one line that is used to declare a constructor, invoking the constructor of the parent class:

class Arched(private val window: Window) : WindowDecorator(window)

We also override the getDescription() and getPrice() functions in the Arched concrete decorator. As this is the wrapping of the window in an Arched type, we need to concatenate the description and find the total price for both the Window and the decorator classes. We do this by overriding the getDescription() and getPrice() functions in the decorator class.

Now we need to modify the main() function that we wrote for verifying the decorator pattern:

fun main(args: Array<String>) {

var window: Window = LargeWindow()
window = Arched(window)
window = Glass(window)
window = BrightSilver(window)

println("Window description: ${window.getDescription()}")
println("Window price: $${window.getPrice()}")

}

In the main function, we create a Window instance, which happens to be LargeWindow, and then wrap it around the Arched, Glass, and BrightSilver decorator types.

When we run this code, we should expect the Window created to be Arched in shape, BrightSilver in color, and made of Glass. The price should also be the sum of the Window($50), Arched($15), Glass($10), and BrightSilver($20), which comes to $95. Consider the following screenshot:

We started with the LargeWindow type, wrapping this around the Arched, Glass, and BrightSilver decorator types. In the end, the instance window will be a BrightSilver type and when we invoke the getDescription() and getPrice() functions, this invokes the overridden version of these functions from the BrightSilver class.

Whenever we want to create a window of different combinations or add a new decor type, we just have to create a new decorator and wrap the component that needs to be decorated. Consequently, following the decorator pattern, we won't run into a class-explosion problem for all the possible combinations of the decor that we need to apply to an object type. This makes adding the new functionality/decor easier and the application therefore becomes more maintainable.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset