It’s a kinda Design Pattern.
How and when do we need to use it?
The Factory method is a creational pattern used to create objects when –
- A class cannot anticipate the type of objects it needs to create beforehand.
- You want to localize the logic to instantiate a complex object.
- You need several “constructors” with the same parameter type but with different behavior.
Imagine we have a parent class called Weapon and two classes more inherited from this one which is AK47 and Kar98k.
abstract class Weapon(
open val id: Int,
open val muzzle: String,
open val barrel: String,
open val underBarrel: String,
open val optic: String,
open val magazine: String,
open val rearGrip: String,
open val stock: String
)
For this example imagine our app will be about weapon loadout generator for Call of Duty Cold War/Warzone game and the user or gamer has to select between AK47 and Kar98k.
AK47 and Kar98k classes –
class AK47(
override val id: Int,
override val muzzle: String,
override val barrel: String,
override val underBarrel: String,
override val optic: String,
override val magazine: String,
override val rearGrip: String,
override val stock: String
): Weapon(id, muzzle, barrel, underBarrel, optic, magazine, rearGrip, stock)
class Kar98k(
override val id: Int,
override val muzzle: String,
override val barrel: String,
override val underBarrel: String,
override val optic: String,
override val magazine: String,
override val rearGrip: String,
override val stock: String
): Weapon(id, muzzle, barrel, underBarrel, optic, magazine, rearGrip, stock)
Suppose our user or gamers or client wants a weapon loadout but we don’t know which one he wants, this would be a very good case to use the factory method because we will make a class or rather a singleton called factory with a method called createWeaponLoadOut
that will return a weapon subclass depending on the choice of the user or gamer, so we will make instances of weapon only with this factory singleton.
Create an Enum first. This enum class is about the list of weapon names.
enum class WeaponList{
AK47 , Kar98k, GRAV, XM4, KRIG6, QBZ83, FFAR1, GROZA, FARA83, C58, EM2, MP5, MILANO821, AK74U
}
Now create WeaponFactory
singleton object
object WeaponFactory{
private var counterId = 0
fun createWeaponLoadOut(weapon: WeaponList,
muzzle: String,
barrel: String,
underBarrel: String,
optic: String,
magazine: String,
rearGrip: String,
stock: String): Weapon?{
return when(weapon){
WeaponList.AK47 -> AK47(counterId++, muzzle, barrel, underBarrel, optic, magazine, rearGrip, stock)
WeaponList.Kar98k -> Kar98k(counterId++, muzzle, barrel, underBarrel, optic, magazine, rearGrip, stock)
else -> {
print("We don't have that weapon here")
null
}
}
}
}
Inside our class, we will have out a method called createWeaponLoadOut()
that will call every time we need to make a new instance of weapon subclasses, we also have a member variable called counterId, this one will provide us a unique for each instance of weapon we make, we also have an enum class called WeaponList
that will let the user choose only between AK47 and Kar98K, otherwise, it will return null.
Now you can print your weapon details like below.
val ak47 = WeaponFactory.createWeaponLoadOut(WeaponList.AK47, "GRU Suppressor", "15.5 inch Ultralight", "Spetsnaz Speedgrip", "Axial Arms 3x", "Bakelite 60 Rnd", "Airborne Elastic Wrap", "KGB Skeletal Stock")
val kar98k = WeaponFactory.createWeaponLoadOut(WeaponList.Kar98k, "GRU Suppressor", "21.5 inch Ranger", "NA", "Variable Scope", "NA", "Airborne Elastic Wrap", "Task Force Stock")
print(ak47?.barrel)
print(kar98k?.underBarrel)
print(ak47?.optic)
print(kar98k?.id)
//Output: 15.5 inch UltralightNAAxial Arms 3x1
Below you can Run full code on Kotlin Playground
fun main() {
val ak47 = WeaponFactory.createWeapon(WeaponList.AK47, "GRU Suppressor", "15.5 inch Ultralight", "Spetsnaz Speedgrip", "Axial Arms 3x", "Bakelite 60 Rnd", "Airborne Elastic Wrap", "KGB Skeletal Stock")
val kar98k = WeaponFactory.createWeapon(WeaponList.Kar98k, "GRU Suppressor", "21.5 inch Ranger", "NA", "Variable Scope", "NA", "Airborne Elastic Wrap", "Task Force Stock")
print(ak47?.barrel)
print(kar98k?.underBarrel)
print(ak47?.optic)
print(kar98k?.id)
}
abstract class Weapon(
open val id: Int,
open val muzzle: String,
open val barrel: String,
open val underBarrel: String,
open val optic: String,
open val magazine: String,
open val rearGrip: String,
open val stock: String
)
class AK47(
override val id: Int,
override val muzzle: String,
override val barrel: String,
override val underBarrel: String,
override val optic: String,
override val magazine: String,
override val rearGrip: String,
override val stock: String
): Weapon(id, muzzle, barrel, underBarrel, optic, magazine, rearGrip, stock)
class Kar98k(
override val id: Int,
override val muzzle: String,
override val barrel: String,
override val underBarrel: String,
override val optic: String,
override val magazine: String,
override val rearGrip: String,
override val stock: String
): Weapon(id, muzzle, barrel, underBarrel, optic, magazine, rearGrip, stock)
enum class WeaponList{
AK47 , Kar98k, GRAV, XM4, KRIG6, QBZ83, FFAR1, GROZA, FARA83, C58, EM2, MP5, MILANO821, AK74U
}
object WeaponFactory{
private var counterId = 0
fun createWeapon(weapon: WeaponList,
muzzle: String,
barrel: String,
underBarrel: String,
optic: String,
magazine: String,
rearGrip: String,
stock: String): Weapon?{
return when(weapon){
WeaponList.AK47 -> AK47(counterId++, muzzle, barrel, underBarrel, optic, magazine, rearGrip, stock)
WeaponList.Kar98k -> Kar98k(counterId++, muzzle, barrel, underBarrel, optic, magazine, rearGrip, stock)
else -> {
print("We don't have that weapon here")
null
}
}
}
}
//Output: 15.5 inch UltralightNAAxial Arms 3x1