Why does the author define a blank interface in a project?

Viewed 243

The following code is from the project https://github.com/skydoves/Pokedex

I can't understand why the author need define a blank interface Repository.

What are the benefit using a blank interface Repository ?

Repository.kt

/** Repository is an interface for configuring base repository classes. */
interface Repository

DetailRepository.kt

class DetailRepository @Inject constructor(
  private val pokedexClient: PokedexClient,
  private val pokemonInfoDao: PokemonInfoDao
) : Repository {
   ...
}

MainRepository.kt

class MainRepository @Inject constructor(
  private val pokedexClient: PokedexClient,
  private val pokemonDao: PokemonDao
) : Repository {
   ...
}
2 Answers

It is called Marker interface pattern. It is interface without any methods or constants. Usually interfaces like this are created to provide special behaviour for a marked classes. You can find a few interfaces like this in java. For example Cloneable and Serializable.

In case of Pokedex i think the reason is much simpler. It looks like this interface was created just to group all repositories. Repository abstraction is never used in the project. Author is always using specific implementations. Repository interface is redundant but can be useful when we want to find all repositories in the project :)

I believe it's because of generics. If you want to create/use an object with generics, the interface will help you a lot.

Consider the following:

interface Animal
class Dog(name:String): Animal{
   fun bark(){
     println("woff")
   }
}
class Cat(name:String): Animal{
   fun meow(){
     println("meow")
   }
}
class Car(name:String){
   fun horn(){
     println("beep")
   }
}
class Farm{
   private val animals = ArrayList<Animals>()
   
   fun addAnimal(animal: Animal){
      // Even if you don't need a direct function from animal
      // you can still store only animals and not cars!
      animals.add(animal)
   }
}
class Main{
   fun main(){
      var farm = Farm()
      farm.addAnimal(Dog("rex"))       // OK
      farm.addAnimal(Cat("luna"))      // OK
      farm.addAnimal(Car("bentley"))   // ERROR
   }
}

Like this, you can enforce the developer to use the tool as you thought of it, avoiding populating objects with general-purpose items.

A further thought could be if you wanted to add some functionalities and you see at some point, that your class repository actually needs a function for each implementation. If you already have an interface, you won't have to worry to search for all possible implementations (maybe the implementation is in one project extending yours), as the compiler will tell you what is missing.

Related