Skip to content

Commit 2460d47

Browse files
refactored Chain Of Responsibilities and Factory Method
1 parent a35aad3 commit 2460d47

File tree

4 files changed

+119
-75
lines changed

4 files changed

+119
-75
lines changed

src/main/kotlin/design_patterns/Factory Method.kt

+48-18
Original file line numberDiff line numberDiff line change
@@ -10,33 +10,63 @@ package design_patterns
1010
*
1111
*/
1212

13-
abstract class Pony
13+
abstract class House(private val address: String, private val price: Int) {
1414

15-
class EarthPony4 : Pony()
16-
class Pegasus4 : Pony()
17-
class Unicorn4 : Pony()
15+
override fun toString() = """
16+
address = $address
17+
price = $price
18+
""".trimIndent()
1819

19-
abstract class Place {
20-
private var numberOfPonies = 0
20+
}
21+
22+
// the factory method makes sense if we have a hierarchy of objects
23+
class WoodenCheapHouse(address: String) : House(address, 50_000)
24+
class WoodenAverageHouse(address: String) : House(address, 250_000)
25+
class WoodenExpensiveHouse(address: String) : House(address, 1_000_000)
26+
27+
class StoneCheapHouse(address: String) : House(address, 45_000)
28+
class StoneAverageHouse(address: String) : House(address, 230_000)
29+
class StoneExpensiveHouse(address: String) : House(address, 900_000)
30+
31+
// we have a common logic for every HouseCompany
32+
abstract class HouseCompany {
2133

22-
abstract fun pony() : Pony
34+
private val alreadyBuiltHouses = mutableListOf<House>()
2335

24-
fun newPony() : Pony {
25-
numberOfPonies++
26-
return pony()
36+
val examplesAlreadyBuiltHouses: String
37+
get() = alreadyBuiltHouses.joinToString("\n\n")
38+
39+
fun orderHouse(address: String, cost: HouseCompanyCost): House {
40+
val house = buildHouse(address, cost)
41+
alreadyBuiltHouses.add(house)
42+
return house
2743
}
2844

29-
fun count() = numberOfPonies
30-
}
45+
// the subclasses define a specific implementation
46+
protected abstract fun buildHouse(address: String, cost: HouseCompanyCost): House
47+
48+
enum class HouseCompanyCost { CHEAP, AVERAGE, EXPENSIVE }
3149

32-
class Cloudsdale : Place() {
33-
override fun pony() = Pegasus4()
3450
}
3551

36-
class Canterlot : Place() {
37-
override fun pony() = Unicorn4()
52+
// WoodenHouseCompany only builds wooden houses
53+
class WoodenHouseCompany : HouseCompany() {
54+
55+
override fun buildHouse(address: String, cost: HouseCompanyCost) = when(cost) {
56+
HouseCompanyCost.CHEAP -> WoodenCheapHouse(address)
57+
HouseCompanyCost.AVERAGE -> WoodenAverageHouse(address)
58+
HouseCompanyCost.EXPENSIVE -> WoodenExpensiveHouse(address)
59+
}
60+
3861
}
3962

40-
class Ponyville : Place() {
41-
override fun pony() = EarthPony4()
63+
// StoneHouseCompany only builds stone houses
64+
class StoneHouseCompany : HouseCompany() {
65+
66+
override fun buildHouse(address: String, cost: HouseCompanyCost) = when(cost) {
67+
HouseCompanyCost.CHEAP -> StoneCheapHouse(address)
68+
HouseCompanyCost.AVERAGE -> StoneAverageHouse(address)
69+
HouseCompanyCost.EXPENSIVE -> StoneExpensiveHouse(address)
70+
}
71+
4272
}

src/main/kotlin/design_patterns/Сhain Of Responsibilities.kt

+16-30
Original file line numberDiff line numberDiff line change
@@ -2,58 +2,44 @@ package design_patterns
22

33
/**
44
*
5-
* pattern: Chain of responsibility
5+
* Chain of responsibility is a behavioral design pattern that allows requests to be sent sequentially
66
*
7-
* description: a design pattern consisting of “a source of command objects and a series of processing objects”.
8-
* Each processing object in the chain is responsible for a certain type of command, and the processing is done,
9-
* it forwards the command to the next processor in the chain.
7+
* through a chain of handlers
108
*
119
*/
1210

13-
enum class BlockFactor {
14-
ONE, TWO, THREE
15-
}
11+
enum class BlockFactor { ONE, TWO, THREE }
1612

17-
/**
18-
* I decided to give an analogy from the Minecraft game.
19-
* In this game there are blocks that can be broken with a stone pickaxe, iron and diamond.
20-
* For example: diamond may mine by iron and diamond pickaxes unlike cobblestone, which is mined by any
21-
*/
13+
// I decided to give an analogy from the Minecraft game.
14+
// In this game there are blocks that can be broken with a stone pickaxe, iron and diamond.
15+
// For example: diamond may mine by iron and diamond pickaxes unlike cobblestone, which is mined by any pickaxe
2216
abstract class Block(private val factor: BlockFactor) {
2317
fun mayMine(factor: BlockFactor) = this.factor.ordinal <= factor.ordinal
2418
}
2519

26-
/**
27-
* blocks from the game
28-
*/
20+
// the blocks are from the game
2921
class StoneBlock: Block(BlockFactor.ONE)
3022
class DiamondBlock: Block(BlockFactor.TWO)
3123
class ObsidianBlock: Block(BlockFactor.THREE)
3224

3325
abstract class Pickaxe(private val factor: BlockFactor) {
3426

3527
private var nextPickaxe: Pickaxe? = null
28+
3629
fun changeNextPickaxe(pickaxe: Pickaxe) {
37-
this.nextPickaxe = pickaxe
30+
nextPickaxe = pickaxe
3831
}
3932

40-
/**
41-
* we mine the block, if it doesn't work, we take another pickaxe, if there is one
42-
*
43-
* @return return true if a pickaxe can mine
44-
*/
45-
fun mine(block: Block): Boolean =
46-
if (block.mayMine(factor)) {
47-
true
48-
} else {
49-
nextPickaxe?.mine(block) ?: false
50-
}
33+
// we mine the block, if it doesn't work, we take another pickaxe, if there is one, returns true if a pickaxe can mine
34+
fun mine(block: Block): Boolean {
35+
if (block.mayMine(factor)) return true
36+
37+
return nextPickaxe?.mine(block) ?: false
38+
}
5139

5240
}
5341

54-
/**
55-
* pickaxes from the game
56-
*/
42+
// the pickaxes are from the game
5743
class StonePickaxe: Pickaxe(BlockFactor.ONE)
5844

5945
class IronPickaxe: Pickaxe(BlockFactor.TWO)

src/test/kotlin/design_patterns/ChainOfResponsibilitiesTest.kt

+8-8
Original file line numberDiff line numberDiff line change
@@ -26,15 +26,15 @@ class ChainOfResponsibilitiesTest {
2626

2727
@Test
2828
fun test_when_we_have_all_three_pickaxes() {
29-
val pickaxe = StonePickaxe()
30-
val ironPickaxe = IronPickaxe().apply {
31-
changeNextPickaxe(DiamondPickaxe())
32-
}
33-
pickaxe.changeNextPickaxe(ironPickaxe)
29+
val ironPickaxe = IronPickaxe()
30+
ironPickaxe.changeNextPickaxe(DiamondPickaxe())
3431

35-
assertEquals(true, pickaxe.mine(StoneBlock()))
36-
assertEquals(true, pickaxe.mine(DiamondBlock()))
37-
assertEquals(true, pickaxe.mine(ObsidianBlock()))
32+
val stonePickaxe = StonePickaxe()
33+
stonePickaxe.changeNextPickaxe(ironPickaxe)
34+
35+
assertEquals(true, stonePickaxe.mine(StoneBlock()))
36+
assertEquals(true, stonePickaxe.mine(DiamondBlock()))
37+
assertEquals(true, stonePickaxe.mine(ObsidianBlock()))
3838
}
3939

4040
}

src/test/kotlin/design_patterns/FactoryMethodTest.kt

+47-19
Original file line numberDiff line numberDiff line change
@@ -2,33 +2,61 @@ package design_patterns
22

33
import org.hamcrest.MatcherAssert.assertThat
44
import org.hamcrest.core.IsInstanceOf.instanceOf
5-
import org.junit.Test
65
import org.junit.Assert.assertEquals
6+
import org.junit.Test
77

88
class FactoryMethodTest {
99

1010
@Test
11-
fun test_match_objects() {
12-
val ponyville = Ponyville()
13-
val earthPony = ponyville.newPony()
14-
15-
assertThat(earthPony, instanceOf(EarthPony4::class.java))
16-
17-
val canterlot = Canterlot()
18-
val unicorn = canterlot.newPony()
19-
20-
assertThat(unicorn, instanceOf(Unicorn4::class.java))
11+
fun `test WoodenHouseCompany`() {
12+
val woodenHouseCompany = WoodenHouseCompany()
13+
14+
val house1 = woodenHouseCompany.orderHouse("77, Brook Ave", HouseCompany.HouseCompanyCost.CHEAP)
15+
assertThat(house1, instanceOf(WoodenCheapHouse::class.java))
16+
17+
val house2 = woodenHouseCompany.orderHouse("77, Brook Ave", HouseCompany.HouseCompanyCost.AVERAGE)
18+
assertThat(house2, instanceOf(WoodenAverageHouse::class.java))
19+
20+
val house3 = woodenHouseCompany.orderHouse("77, Brook Ave", HouseCompany.HouseCompanyCost.EXPENSIVE)
21+
assertThat(house3, instanceOf(WoodenExpensiveHouse::class.java))
22+
23+
val expected = """
24+
address = 77, Brook Ave
25+
price = 50000
26+
27+
address = 77, Brook Ave
28+
price = 250000
29+
30+
address = 77, Brook Ave
31+
price = 1000000
32+
""".trimIndent()
33+
assertEquals(expected, woodenHouseCompany.examplesAlreadyBuiltHouses)
2134
}
2235

2336
@Test
24-
fun test_count() {
25-
val cloudsDale = Cloudsdale()
26-
27-
cloudsDale.newPony()
28-
cloudsDale.newPony()
29-
cloudsDale.newPony()
30-
31-
assertEquals(3, cloudsDale.count())
37+
fun `test StoneHouseCompany`() {
38+
val stoneHouseCompany = StoneHouseCompany()
39+
40+
val house1 = stoneHouseCompany.orderHouse("55, Brook Ave", HouseCompany.HouseCompanyCost.CHEAP)
41+
assertThat(house1, instanceOf(StoneCheapHouse::class.java))
42+
43+
val house2 = stoneHouseCompany.orderHouse("55, Brook Ave", HouseCompany.HouseCompanyCost.AVERAGE)
44+
assertThat(house2, instanceOf(StoneAverageHouse::class.java))
45+
46+
val house3 = stoneHouseCompany.orderHouse("55, Brook Ave", HouseCompany.HouseCompanyCost.EXPENSIVE)
47+
assertThat(house3, instanceOf(StoneExpensiveHouse::class.java))
48+
49+
val expected = """
50+
address = 55, Brook Ave
51+
price = 45000
52+
53+
address = 55, Brook Ave
54+
price = 230000
55+
56+
address = 55, Brook Ave
57+
price = 900000
58+
""".trimIndent()
59+
assertEquals(expected, stoneHouseCompany.examplesAlreadyBuiltHouses)
3260
}
3361

3462
}

0 commit comments

Comments
 (0)