w3resource

Kotlin decorator pattern: Modifying component behavior


Write a Kotlin object-oriented program that implements the decorator pattern by creating a base class Component and decorator classes BoldDecorator and ItalicDecorator to modify the behavior of the component.


Pre-Knowledge (Before You Start!)

Before attempting this exercise, you should be familiar with the following concepts:

  • Interfaces: Understanding how to define and implement interfaces in Kotlin.
  • Decorator Pattern: A structural design pattern that allows behavior to be added to objects dynamically without modifying their existing code.
  • Inheritance: How to create a base class and extend it using subclasses.
  • Super Keyword: Using super to call methods from a parent class.
  • Composition: Instead of modifying a class directly, using another class to wrap and extend its functionality.

Hints (Try Before Looking at the Solution!)

Try to solve the problem using these hints:

  • Hint 1: Define a Component interface with a method render() that returns a string.
  • Hint 2: Create a ConcreteComponent class that implements the Component interface and provides a basic implementation of render().
  • Hint 3: Create an abstract decorator class TextDecorator that implements the Component interface and delegates the render() method to the wrapped component.
  • Hint 4: Implement a BoldDecorator that overrides the render() method to wrap text in <b> ... </b>.
  • Hint 5: Implement an ItalicDecorator that overrides the render() method to wrap text in <i> ... </i>.
  • Hint 6: In the main() function, create instances of the decorators and wrap them around the ConcreteComponent to test different formatting options.

Sample Solution:

Kotlin Code:

interface Component {
    fun render(): String
}

class ConcreteComponent : Component {
    override fun render(): String {
        return "Original component: Kotlin OOP"
    }
}

abstract class TextDecorator(private val component: Component) : Component {
    override fun render(): String {
        return component.render()
    }
}

class BoldDecorator(component: Component) : TextDecorator(component) {
    override fun render(): String {
        val renderedText = super.render()
        return "<b>$renderedText</b>"
    }
}

class ItalicDecorator(component: Component) : TextDecorator(component) {
    override fun render(): String {
        val renderedText = super.render()
        return "<i>$renderedText</i>"
    }
}

fun main() {
    val originalComponent: Component = ConcreteComponent()
    val boldDecorator: Component = BoldDecorator(originalComponent)
    val italicDecorator: Component = ItalicDecorator(originalComponent)
    val boldItalicDecorator: Component = ItalicDecorator(BoldDecorator(originalComponent))

    println("Original: ${originalComponent.render()}")
    println("Bold Decorator: ${boldDecorator.render()}")
    println("Italic Decorator: ${italicDecorator.render()}")
    println("Bold Italic Decorator: ${boldItalicDecorator.render()}")
}

Sample Output:

Original: Original component: Kotlin OOP
Bold Decorator: <b>Original component: Kotlin OOP</b>
Italic Decorator: <i>Original component: Kotlin OOP</i>
Bold Italic Decorator: <i><b>Original component: Kotlin OOP</b></i>

Explanation:

In the above exercise -

  • We have an interface Component that defines the common behavior for all components. The ConcreteComponent class implements the Component interface, representing the original component.
  • "TextDecorator" is an abstract class that implements the Component interface and holds a reference to another component. It acts as a base class for specific decorators.
  • "BoldDecorator" and "ItalicDecorator" are concrete decorator classes that extend "TextDecorator". They override the render() method to modify the wrapped component's behavior. In this case, they add HTML tags <b> and <i> to the rendered text.
  • In the main() function, we create instances of the original component and different decorators. The decorators modify the original component's behavior by calling render() on each of them.

Go to:


PREV : Handling operation results.
NEXT : Creating animal instances.

Kotlin Editor:


Improve this sample solution and post your code through Disqus

What is the difficulty level of this exercise?

Test your Programming skills with w3resource's quiz.



Follow us on Facebook and Twitter for latest update.