Factory And Abstract Factory in Android

hitender pannu
7 min readJan 20, 2019

--

Design Patterns have long been considered some of the most reliable and useful approaches for solving common software design problems.

Patterns provide general and reusable solutions to frequently occurring development issues, such as how to add functionality to an object without changing its structure or how to construct complex objects.

Most of the android developers started their development carrier with Android without having a complete understanding of the software architecture principles and design patterns. Though in the small applications these things work out but, as the application grows the bug count increases, the code base becomes messy.

To avoid these scenarios it is very important to understand the different patterns that are developed over the past years and are helping the developers in developing and maintaining large scale applications.

In this series, I will be discussing a number of patterns that can be used in Android applications.

Today I will be going through the Factory and Abstract Factory patterns. We will start from a very simple code base and iterate over the implementations to improve it and make use of these patterns.

Let's get started

For implementing the design patterns, we should understand the use case and the problem we are trying to solve. For our series, I will be building an app for a restaurant which delivers sandwiches you can think of it as the Subway.

Our app allows a user to create their own customized sandwich in which they can choose the kind of bread or the filling they wish to have.

Ok! Now, this sounds easy right, all we need to do is to create a different class for every bread type and every filling. We will give options to the user to select among those and we will be done right.

So, let's do that -

class Baguette {
fun getName(): String {
return "Baguette";
}

fun getCaloriesCount(): String {
return "65 kcal"
}
}

class Brioche {
fun getName(): String {
return "Brioche"
}

fun getCaloriesCount(): String {
return "85 kcal"
}
}

class Cheese {
fun getName(): String {
return "Cheese"
}

fun getCaloriesCount(): String {
return "105 kcal";
}
}

class Tomato {
fun getName(): String {
return "Tomato"
}

fun getCaloriesCount(): String {
return "60 kcal"
}
}

We have our classes for bread and fillings, now we are ready to use them and nothing will go wrong here if we are careful enough while using these classes.

Let’s use them

val bread = Brioche()
val filling = Tomato()

This looks good. We have created a new object Brioche and Tomato and assigned it to our bread and filling variables but there is a small problem as we know that Brioche is bread and Tomato is a filling but our code has no idea.

So what to do now?

Ok, We know how to fix this we need to create a “type” using interface and make our classes implement that interface.

Let's do that

interface Bread {}interface Filling {}

And our class will become.

class Baguette : Bread{
fun getName(): String {
return "Baguette";
}

fun getCaloriesCount(): String {
return "65 kcal"
}
}

class Brioche : Bread{
fun getName(): String {
return "Brioche"
}

fun getCaloriesCount(): String {
return "85 kcal"
}
}

class Cheese : Filling{
fun getName(): String {
return "Cheese"
}

fun getCaloriesCount(): String {
return "105 kcal";
}
}

class Tomato : Filling{
fun getName(): String {
return "Tomato"
}

fun getCaloriesCount(): String {
return "60 kcal"
}
}

Cool, let's take another look at the code. We have common methods, and we can include them in our interfaces.

interface Bread {
fun getName(): String;
fun getCaloriesCount(): String;
}

interface Filling {
fun getName():String
fun getCaloriesCount():String
}

And our classes will become.

class Baguette : Bread{
override fun getName(): String {
return "Baguette";
}

override fun getCaloriesCount(): String {
return "65 kcal"
}
}

class Brioche : Bread{
override fun getName(): String {
return "Brioche"
}

override fun getCaloriesCount(): String {
return "85 kcal"
}
}

class Roll : Bread {
override fun getName(): String {
return "Roll"
}

override fun getCaloriesCount(): String {
return "75 kcal"
}
}

class Cheese : Filling{
override fun getName(): String {
return "Cheese"
}

override fun getCaloriesCount(): String {
return "105 kcal";
}
}

class Tomato : Filling{
override fun getName(): String {
return "Tomato"
}

override fun getCaloriesCount(): String {
return "60 kcal"
}
}

This is perfect, now it will be easy to differentiate that bread and fillings.

But our usage code still looks the same. We still need to use the constructor of Brioche and Tomato. Wouldn’t it be nice if we can have someone to whom we can say “hey, I want this type of bread” and it will just create it and give it to us saving us from writing the constructor logic?
This is where the factory pattern comes into the picture. We just tell our factory that we want this type of object and it will create it and give it to us saving us from the constructor logic.
One thing to note here is that a factory should return only a single type of object.

class BreadFactory {
fun getBread(breadType: String): Bread? {
return when (breadType) {
"BRI" -> Brioche()
"BAG" -> Baguette()
"ROL" -> Roll()
else -> null
}
}
}
class FillingFactory {
fun getFilling(fillingType: String): Filling? {
return when (fillingType) {
"CHE" -> Cheese()
"TOM" -> Tomato()
else -> null
}
}
}

Now, we can make use them like

val breadFactory = BreadFactory().getBread("BRI")
val fillingFactory = FillingFactory().getFilling("TOM")

The additional benefit of this is that by looking at our factory we can know all the types of bread or types of fillings supported. This also makes it easy to add more types or breads and fillings.

What we did above is called factory pattern i.e creating a factory that will return us a particular type of object separating the construction logic from use.

Everything looks good here and our app is also looking great and things are working perfectly as expected. Now with the growth of the business, We want to introduce more items in our app e.g drinks, cookies etc.

We can go ahead and create DrinkFactory and CookieFactory respectively and we should be able to use them without any issue.

Let's have another look at our code base and see if we can improve it.

When we look at any factory, we know all the implementations it can provide, wouldn’t be nice if we can have a factory which can provide us with different factories. In this way can make a single point of getting all the factories and our code base will be more organized.

We know that a factory returns the same type of object so let's create that type.

abstract class AbstractFactory {

abstract fun getBread(breadType: String): Bread?

abstract fun getFilling(fillingType: String): Filling?
}

Now we will create a factory which will return other factory let’s call it FactoryGenerator.

class FactoryGenerator {

companion object {
fun getFactory(factory: String): AbstractFactory? {
return when (factory) {
"BRE" -> BreadFactory();
"FIL" -> FillingFactory();
else -> null
}
}
}
}

We also need to make our factories extend the AbstractFactory.

class BreadFactory : AbstractFactory() {
override fun getBread(breadType: String): Bread? {
return when (breadType) {
"BRI" -> Brioche()
"BAG" -> Baguette()
"ROL" -> Roll()
else -> null
}
}

override fun getFilling(fillingType: String): Filling? {
return throw UnsupportedOperationException();
}
}
class FillingFactory : AbstractFactory() {
override fun getBread(breadType: String): Bread? {
return throw UnsupportedOperationException();
}

override fun getFilling(fillingType: String): Filling? {
return when (fillingType) {
"CHE" -> Cheese()
"TOM" -> Tomato()
else -> null
}
}
}

We can use them like

val breadFactory = FactoryGenerator.getFactory("BRE")
val bread = breadFactory?.getBread("ROL");

val fillingFactory = FactoryGenerator.getFactory("FIL")
val filling = fillingFactory?.getFilling("CHE")

what we did now is called Abstract Factory Pattern i.e. A Factory that returns other factories.

BONUS:
If you like generics we can modify our abstract factory, a little and our code will change like this

abstract class AbstractFactory<T> {
abstract fun getItem(type: String): T?
}
class BreadFactory : AbstractFactory<Bread>() {
override fun getItem(type: String): Bread? {
return when (type) {
"BRI" -> Brioche()
"BAG" -> Baguette()
"ROL" -> Roll()
else -> null
}
}
}
class FillingFactory : AbstractFactory<Filling>() {
override fun getItem(type: String): Filling? {
return when (type) {
"CHE" -> Cheese()
"TOM" -> Tomato()
else -> null
}
}
}
class FactoryGenerator {

companion object {
fun getBreadFactory(): AbstractFactory<Bread> {
return BreadFactory();
}

fun getFillingFactory(): AbstractFactory<Filling> {
return FillingFactory();
}
}
}
val breadFactory = FactoryGenerator.getBreadFactory()
val bread = breadFactory.getItem("ROL");

val fillingFactory = FactoryGenerator.getFillingFactory()
val filling = fillingFactory.getItem("TOM")

You can also create a live template for this. I have created one you can add it by going to Preferences-> Editor-> Live Templates-> kotlin

and then we can use it like

Thanks for spending your valuable time by reading this article. I hope it helps you out in one or another way-

Next, I will also be sharing more about other design patterns and how we can use them in our apps.

--

--