|The Programmers Guide To Kotlin - Inheritance|
|Written by Mike James|
|Monday, 07 August 2017|
Page 3 of 3
As if classes, interfaces and abstract classes weren't enough ways to handle inheritance Koltin also supports delegation.
Delegation in its most general form simply means creating an instance of a class within another class and then using its methods to implement the containing class's methods. This is supposed to be a safer form of "inheritance" and you will hear the saying "prefer composition to inheritance". Composition is where one object acquires the methods of another by simply containing an instance of the object. Calls to the methods of the contained object are simply passed onto it by the containing object - a sort of delegation.
This is simple and direct but manually creating all of the methods needed redirect calls to the object that does all of the work is tedious and error prone.
For example suppose we have an Printer class that prints some messages. We could use inheritance to give a derived class the same methods. Alternatively we could achieve the same result by creating an instance of the Printer class within our derived class. That is given the class:
You can use manual delegation to implement a "derived" class which has the same myFunc method implemented by the existing Printer class quite simply:
You can see that we have created an instance of the Printer class and then used it to implement the new myFunc method.
This is delegation in action and it is simple but if there are very many methods to delegate very tedious.
Kotlin will do automatic delegation for you but there are some limitations.
The first is that you have to have an interface defined that specifies all of the methods that are going to be delegated. Next you have to have an object that implements the interface. You can get an object that implements the interface either by creating a class that implements the interface and then creating and instance or directly creating an object. Once you have the object the derived class can delegate all of the interface methods to the object using the keyword by.
For example to delegate the Printer methods as before we would first define an interface that specifies the methods to be automatically delegated:
There is just one method in this case but in general there will be a list of virtual and implemented methods. Next we have to create an object that implements these methods:
Now we can create a "derived" class that delegates all of the calls to the methods in the interface to the object that implements the interface:
You can now create an instance of MyClassA and call the myFunc method which is implemented automatically by the system as a call to printer.myFunc(mess).
As already stated you could create a Printer class that implemented the Iprinter interface and then use an instance as the object that is delegated to. Also notice that while the body of the derived class is emtpy in this example you can override the delegated methods and provide a new implementation.
At first sight automatic delegation seems like a powerful feature but the need to define an interface and then implement it makes it less so. Manual delegation can take any object and use it to create a derived class by delegation even if the "base" class is final and cannot be used by inheritance. However automatic delegation needs the "base" class to implement the interface of methods to be delegated. What this means is that the base class has to be prepared for delegation just as much as for inheritance.
Notice that in inheritance a class inherits from another class but in delegation a class inherits from an object.
Visibility Modifiers, Packages and Modules
In the introduction it was explained that the way to tame inheritance is to control access to the inner workings of a class. If the outside world can only make use of what the class does and not how it does it then changes to the base class that doesn't alter what it does should be safe.
To control access to classes and class members Kotlin has four visibility modifiers and while their meanings depend on context their intent is clear:
When applied to the members of a class or interface these have obvious meanings. Public means that the method or property is accessible and private means they aren't. Notice that the inner workings of a method aren't accessible outside of a class even if declared public. This is a special case of the more general rule that local variables are always inaccessible.
Also notice that an outer class doesn't see the private members of an inner class.
You can also apply visibility modifiers to constructors.
Kotlin also uses the idea of a package and a module to control access. Packages work roughly the same way that they do in Java. A source file can declare itself a member of a package using:
following this the fully qualified name of any class or function has mypackage.myname prefixed e.g. mypackage.myname.MyClass.
In other languages a package would be called a namespace.
If another source file wants to use something from another package it has to import it.
and to import everything in the package you can use a wild card:
A class can also be assigned an alias to resolve name clashes -
import mypackage.myname.MyClass as AnotherClass
Any private properties or functions declared at the top level of a package i.e. not within a class are visible thoughout the package but not outside of the package.
Kotlin has one other level of organization - the module. This is more like a compiler unit rather than something abstract. A module is
Anything marked as internal in a package is visible everywhere within the module. This is most probably best avoided if possible.
Programmer's Guide To Kotlin Second Edition
You can buy it from: Amazon
or email your comment to: email@example.com
|Last Updated ( Sunday, 10 September 2017 )|