Search code examples
kotlininheritancedesign-patternsoverridingdecorator

Overriding method in separate instantiated class


There are 2 classes inherited from parent:

abstract class Parent{
    abstract fun prepare()
    abstract fun act()
}

class Child1:Parent(){
    fun prepare()
    fun act()
}
class Child2:Parent(){
    fun prepare()
    fun act()
}

I need to modify only method act() just to perform some action before it and run it after:

class Modify (parent:Parent):parent{
    override fun act(){
        ...//modification
        parent.act() //from Child1 or Child2 depends 
    }
}

class Modify1 (parent:Parent):parent{}
class Modify2 (parent:Parent):parent{}

The idea is to have several modificators and use them arbitrarily both for modified and not modified instances along with using several serial modificators:

val modifiedChild1:Parent = Modify1 ( Modify3( Child1() ) )
val modifiedChild2:Parent = Modify1 ( Child2() )
val notModified1:Parent   = Child1 ()

Please advise if this concept is correct and how to implement it. Thanks.

the only way I found: is to add an interface as listener. But in that case, it is not possible to use Modify() as a function and possibility perform several modifications.


Solution

  • If you're interested in modifying the public functions of Parent, you can use the Decorator pattern to create a wrapper class and override the functions. For example:

    // Copyright 2023 Google LLC.
    // SPDX-License-Identifier: Apache-2.0
    
    abstract class Parent {
       abstract fun prepare()
       abstract fun act()
    }
    
    class ParentDecorator(val parent: Parent): Parent() {
       override fun prepare() {
          // modification
          parent.prepare()
          // modification
       }
       override fun act() {
          // modification
          parent.act()
          // modification
       }
    }
    
    class Child: Parent() { ... }
    
    val child = Child()
    val decoratedChild = ParentDecorator(child)
    decoratedChild.prepare()
       // will call the modifications around the call to the 
       // nested child instance
    

    This only works if the parent is abstract, open, or is an interface, and only affects the public functions that you override in the Decorator.

    Note - this example is a tad awkward - we're creating an instance of Parent to override all of its functions and wrap another instance of Parent, delegating the real function to that wrapped instance. It would be much better to make Parent an interface if you want to create a Decorator. For example:

    // Copyright 2023 Google LLC.
    // SPDX-License-Identifier: Apache-2.0
    
    interface Stuff {
       fun prepare()
       fun act()
    }
    
    class StuffDecorator(val realStuff: Stuff): Stuff {
       override fun prepare() {
          // modification
          realStuff.prepare()
          // modification
       }
       override fun act() {
          // modification
          realStuff.act()
          // modification
       }
    }
    
    class Child: Stuff { ... } 
       // could extend another class that implements Stuff
    
    val child = Child()
    val decoratedChild = StuffDecorator(child)
    decoratedChild.prepare()
       // will call the modifications around the call to the 
       // nested child instance
    

    However, if you're stuck with an existing open/abstract Parent class, this is the best you can do)

    If you want to do this is non-public functions, @cyberbrain's mention of AspectJ is more the way to go (but I'm not sure that can work with Kotlin - I see some mentions, such as https://github.com/serpro69/kotlin-aspectj-maven-example/blob/master/README.md, but no idea if that actually works).