Hi, I want to define a factory for an interface fo...
# getting-started
a
Hi, I want to define a factory for an interface for a common library. I want to understand the pros/cons of defining a concrete class vs using anonymous object. Can’t wrap my head on the lines in Object expressions regarding anonymous classes:
Such classes are useful for one-time use
.
Copy code
interface Person {
    val name: String
    val age: Int
}

Option 1
---
fun Person(name: String, age: String): Person = object : Person {
    override val name = name
    override val age = age
}

Option 2
---
fun Person(name: String, age: String): Person = PersonImpl(name, age)

private class PersonImpl(
    override val name: String,
    override val age: String
) : Person
1. What’s the pros/cons between the two? 2. Which is more preferred? 3. What does
one-time use
mean? Does it mean we can’t pass instances of anonymous classes around?
a
Out of order: 3. You usually would use an anonymous object when you need to implement an interface that will be used in only one place, so it's not worth it declaring a separate class. A classic example would be a library function/object that need an onXListener, and instead of creating a new class you simply declare the implementation on the spot using an anonymous object. 1. With an anonymous class you don't need to declare a new class which might end up polluting your project unnecessarily. With the "extending the interface in a separate class" method, you basically make your code more reusable. 2. It depends a lot on the use case. In your example, I'd recommend going the PersonImpl way, as that seems to make more sense. In my opinion, anonymous objects are more appropriate in functional interfaces or callbacks examples.
c
In your example, it looks like your
Person
interface is just a data-holder, which is not a good use-case for anonymous objects. There’s not really a good reason to represent
Person
as an interface instead of just using a
data class
, it’s an unnecessary level of abstraction that makes the code harder to understand. A one-time anonymous object is useful when doing local processing of data that benefits of the readability of discrete properties, but you really don’t need that class anywhere else. Take the following example, where we parse a list of strings into XYZ vectors and find their length: https://pl.kotl.in/wkR1FoHD9 Another use-case is when you have an interface which may have many different implementations, but those implementations are relatively simple and do not warrant having actual class declarations for each. Creating delegate functions with
ReadOnlyProperty
or
ReadWriteProperty
is one such example. As you can see in this file, there are lots of object expressions, but they’re all simple 1-liners (
ReadOnlyProperty
is defined as a
fun interface
which means you can drop the
object :
part and just use a lambda)
I will also add that I’ve never actually needed to do the local-processing of data in any real-world code. If you’re doing something with heavy data-processing (data science, visualization, etc.) you might, but I’m mostly an application developer and have never needed this. But object expressions for setting up callbacks like Android’s
OnClickListener
or creating property delegates is something I do quite frequently
a
You usually would use an anonymous object when you need to implement an interface that will be used in only one place
A one-time anonymous object is useful when doing local processing of data that benefits of the readability of discrete properties, but you really don’t need that class anywhere else
Thanks! These two seems to convey the same message. In this case, I’m only exposing the factory method
Person
as an API and any devs that need to create a
Person
does not need to know about
PersonImpl
class. Does that mean anonymous object can be used here? Just thinking that defining
PersonImpl
is unnecessary boilerplate
k
Perhaps the
Person
example is flawed? If you're talking about a person it makes more sense to have a
data class
rather than an interface, I don't see how the implementation of the interface would have such an intricate logic that needs to be hidden, however if in this example the
Person
interface represents any other component that maybe have a clear harder and complex implementation than just holding data, I'll go with the implementation in a private class:
Copy code
interface Something 

fun Something(): Something = SomethingImpl()

private class SomethingImpl : Something
Just because holding all the logic inside an anonymous object here wouldn't make too much sense
c
Yeah, I’d agree with Kevin. If the consumers of you library only need to access relatively simple data properties, then just use a data class. Consider whether consumers would reasonably do different things with their
PersonImpl
class, or whether it’s just “to avoid coupling” (which is not even true, since the class they create is still coupled to the interface). Java code usually leads too heavily on the interface/impl structure when it’s not really necessary and only makes the code harder to read, and it much less prevalent in Kotlin. In the case where the data is reasonably complex and you can expect each consumer would do different things with it, then it’s advisable to use a concrete class instead of an object expression.
So in this case, consider what the user of your library would actually do with
Person
. Does it represent a logged-in user, where the user may sign in via Twitter, Facebook, Google, etc. and each auth provider needs custom logic for defining what a “Person” is? Then yes, keep it as an interface. But if you only have 1 thing that could be a Person that you manage within the library, then you’re better off using a
data class
instead of
interface
, which gives you additional benefits of things like equals/hashcode and toString automatically
And as an aside, in my experience, I’ve found it’s usually better to define your library using concrete classes and ask your users to “map” their custom structures into those of your library, rather than asking them to implement interfaces and pass their custom classes into your library. It helps you know exactly what your library is doing, and defines strict separation of concerns between the library and the users of it