Delegate a function to all other interfaces - kotlin

I have an interface:
interface EmployeeActions
interface SalesEmployeeActions : EmployeeActions {
fun onSaleRequest()
//..more functions
}
interface HREmployeeActions : EmployeeActions {
}
...//more EmployeeActions
Now the way I am using this in the class is basically an aggregation where I will have many of these objects and I want to call stuff on them all together.
class FakeEmployeeDb {
val employees: MutableList<EmployeeActions> = mutableListOf()
private val salesEmployees:
get() = employees.filterIsInstance<SalesEmployeeActions>()
....
val salesManager = object: SalesEmployeeAction {
fun onSaleRequest() {
salesEmployees.forEach { it.onSaleRequest() }
}
... //more functions
}
private val .... // other Managers
// also at some point employees are added using this API...
fun addEmployee(employee: EmployeeActions) {
employees.add(employee)
}
}
Question:
Is there a kotlin-y way of writing this code in a scalable way?
In the real case, the client will only call APIs on these xyzManager objects and the job of each of them is to simply pass that information down to all employees.

Related

Kotlin Delegation how to access class properties from delegate object

I'm trying to split some work from a giant class to provide more readability. Firstly I looked into Extension but seems like it is just creating some static functions, then delegate pattern came into my eyes.
The below code looks all right, and delegate works as if part of EnhancedProducer class.
But there is one problem that blocking me though, I don't quite get how to access the service property of EnhancedProcuder class from delegate. In my real code, there are some cases that both the original class and delegate class need to use the service variable at the same time, so I don't know if there is a way to do it.
I do understand we can probably inject service instance into both of them but I still want to find out if there is a more elegant way to makes delegate fit into EnhancedProducer class more naturally.
interface Producer {
fun produce()
}
class ProducerImpl : Producer {
override fun produce() {
// service.doSomething() how to access service here
println( "ProducerImpl")
}
}
class EnhancedProducer(private val delegate: Producer) : Producer by delegate {
// how to share this with delegate
//private val service = Service()
fun test() {
produce()
}
}
fun main() {
val producer = EnhancedProducer(ProducerImpl())
producer.test()
}
I have eventually come up with a solution that initialise ProducerImpl right after by keyword. It is so weird that all the examples that I found so far only try to inject an instance rather than providing an initialization when delegation is needed. Maybe someone knows anything about it?
interface Producer {
fun produce()
}
class ProducerImpl(val service:Service) : Producer {
override fun produce() {
service.doSomething()
println(item)
}
}
class EnhancedProducer(val service:Service) : Producer by ProducerImpl(service) {
fun test() {
produce()
}
}
fun main() {
val service = Service()
val producer = EnhancedProducer(service)
}
May use open properties in the interface:
interface Producer {
fun produce()
// two classes will use/modify this property
var service: Service
}
...
class ProducerImpl: Producer {
override var service = Service()
fun changeService() {
service.execute() // access to the interface field
}
}
...
class EnhancedProducer(private val delegate: Producer): Producer by delegate {
fun test() {
this.service // access to the interface field
delegate.service // access to the interface field
produce()
}
}
fun main() {
val producerImpl = ProducerImpl()
val producer = EnhancedProducer(producerImpl)
producerImpl.service // access to the interface field
producer.service // access to the interface field
}

Get a reference to the class of the calling function

When I have two classes (A and B) and A has a function called myFunA which then calls myFunB (inside of class B), is it possible for code in myFunB to obtain a reference to the class A that is used to call myFunB? I can always pass the reference as a parameter but I am wondering if Kotlin has a way of allowing a function to determine the instance of the parent caller.
class A {
fun myFunA() {
val b = B()
b.myFunB() {
}
}
}
class B {
fun myFunB() {
// Is it possible to obtain a reference to the instance of class A that is calling
// this function?
}
}
You can do it like this:
interface BCaller {
fun B.myFunB() = myFunB(this#BCaller)
}
class A : BCaller {
fun myFunA() {
val b = B()
b.myFunB()
}
}
class B {
fun myFunB(bCaller: BCaller) {
// you can use `bCaller` here
}
}
If you need a reflection-based approach, read this.

Runtime polymorphism in Kotlin

Is there any elegant way to apply polymorphism in this case? The parser provides the following classes at runtime:
class io.swagger.v3.oas.models.media.Schema //is parent of the rest :
class io.swagger.v3.oas.models.media.ComposedSchema
class io.swagger.v3.oas.models.media.ArraySchema
class io.swagger.v3.oas.models.media.StringSchema
class io.swagger.v3.oas.models.media.ObjectSchema
I'd like to have function for each class with the same name and simple, short method which will cast and call necessary function at runtime. Which is actually happening, but I hope there is more brief solution, without necessity of making this kind of duplicates:
fun main() {
val parser = OpenAPIV3Parser()
val asList = listOf(pathYaml3, pathYml2)
val map = asList.map(parser::read)
.flatMap { it.components.schemas.values }
.forEach(::parseRawSchema)
}
fun parseRawSchema(schema: Schema<Any>) {
if (schema is ComposedSchema) {
parseSchema(schema)
}
if (schema is StringSchema) {
parseSchema(schema)
}
...
}
fun parseSchema(schema: ComposedSchema) {
println("Compose-schema")
}
fun parseSchema(schema: StringSchema) {
println("Sting-schema")
}
...
Try use extension.
For example:
fun ComposedSchema.parseSchema() {
println("Compose-schema")
}
fun StringSchema.parseSchema() {
println("Sting-schema")
}
And than:
fun parseRawSchema(schema: Schema<Any>) {
schema.parseSchema()
}

Hiding base class constructor parameters in Kotlin

I am trying to understand how to hide a base constructor parameter in a subclass in kotlin. How do you put a facade over a base constructor? This doesn't work:
import com.android.volley.Request
import com.android.volley.Response
class MyCustomRequest(url: String)
: Request<String>(Request.Method.POST, url, hiddenListener) {
private fun hiddenListener() = Response.ErrorListener {
/* super secret listener */
}
...
}
I think I understand the problem:
During construction of a new instance of a derived class, the base
class initialization is done as the first step (preceded only by
evaluation of the arguments for the base class constructor) and thus
happens before the initialization logic of the derived class is run.
I'm trying to solve this problem for Volley, where I need my custom request to be be a Request so that it can be passed into a RequestQueue. It would be easier of RequestQueue took in some kind of interface but since it doesn't I have to subclass. There are other ways I can hide these complexities from the caller, but this limitation has come up for me other times in Kotlin and I'm not sure how to solve it.
I am not familiar with volley but I tried to come up with an example that should give you some insight how to solve your problem. What you can do is use a companion object:
interface MyListener {
fun handleEvent()
}
open class Base<T>(anything: Any, val listener: MyListener) { // this would be your Request class
fun onSomeEvent() {
listener.handleEvent()
}
}
class Derived(anything: Any) : Base<Any>(anything, hiddenListener) { // this would be your MyCustomRequest class
private companion object {
private val hiddenListener = object : MyListener {
override fun handleEvent() {
// do secret stuff here
}
}
}
}
So if you apply this to your problem, the result should look something like this:
class MyCustomRequest(url: String)
: Request<String>(Request.Method.POST, url, hiddenListener) {
private companion object {
private val hiddenListener = Response.ErrorListener {
/* super secret listener */
}
}
...
}
A different way would be to use a decorator, create your Request withing that decorator and just delegate the calls to it:
class Decorator(anything: Any) {
private var inner: Base<Any>
private val hiddenListener: MyListener = object : MyListener {
override fun handleEvent() { }
}
init {
inner = Base(anything, hiddenListener)
}
}
And once again for your example that would look like this:
class MyCustomRequest(url: String) {
private var inner: Request<String>
private val hiddenListener = Response.ErrorListener {
/* super secret listener */
}
init {
inner = Request<String>(Request.Method.POST, url, hiddenListener)
}
...
}

Is there a way to verify that a top-level function passed as a dependency to a class has been called during testing?

I have a class that receives a function allowing it to display things on the UI during a failure case. What's the best way that I can verify that the function is called in my test?
MyClass(private val uiPrinter: (String) -> Unit) {
fun foo() {
// do some stuff
uiPrinter("printing from foo!")
// do some more stuff
}
}
MyClassTest() {
val testUiPrinter: (String) -> Unit = { System.out.println(it) }
#Test
fun uiPrinterIsInvoked() {
val myClass = MyClass(testUiPrinter)
myClass.foo()
// can I verify that testUiPrinter has been invoked?
}
}
You may want to check out the Model-View-Presenter architecture. Its purpose is to hide the Android framework behind an abstract View interface which a purely Java Presenter can interact with. In your example:
interface ViewInterface {
fun printError(error: String)
}
class MyPresenter(private val view: ViewInterface) {
fun foo() {
// do some stuff (testable stuff)
view.printError("Printing from foo()!")
// do some more (testable) stuff
}
}
class MyPresenterTest() { // Test using Mockito to mock the abstract view
private val view = mock(ViewInterface::class.java)
private val presenter = MyPresenter(view)
#Test
fun printsError() {
// set up preconditions
presenter.foo()
verify(view).printError("Printing from foo()!")
}
}
Your concrete view will generally be an Android Activity, Fragment, or View which implements the view interface. Notice MyPresenter only expects the abstract view and does not need knowledge of the framework-dependent operations.
class MyActivity : Activity(), ViewInterface {
// ...
override fun printError(error: String) {
textView.text = error // For example
}
// ...
}
This can be achieved by mocking the higher-order function as higher-order functions are objects unless inlined.
#Mock
val testUiPrinter: (String) -> Unit
#Test
fun uiPrinterIsInvoked() {
val myClass = MyClass(testUiPrinter)
myClass.foo()
verify(testUiPrinter).invoke("Printing from foo!")
}