-
Notifications
You must be signed in to change notification settings - Fork 20
/
Copy pathmodel.kt
133 lines (112 loc) · 3.61 KB
/
model.kt
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
import java.util.ArrayList
/**
* Defines the minimalistic API to allow to form
* Company structure tree
*/
interface Node {
/**
* Name of a node
*/
val name: String
/**
* If Node is a leaf, returns an empty list
* Otherwise returns the list of immediate children of the current
* node.
* This method is crucial to navigate the tree
*/
val children: List<Node>
/**
* Visitor pattern support for Nodes
* to demonstrate double-dispatch mechanism
*
* @see [Visitor Pattern](https://en.wikipedia.org/wiki/Visitor_Pattern)
*
* @see [Double-Dispatch](https://en.wikipedia.org/wiki/Double_dispatch)
*/
fun <U> accept(data: U, visitor: NodeVisitor<U>): U
}
/**
* Visitor interface allows to decouple code that needs to be invoked
* on Node instances from the various ways to enumerate Nodes in the tree
*
* Visitor pattern goes hand-in-hand with Double Dispatch pattern that
* allows to call Node-specific Visitor's method in a type safe manner, without need
* to determine the type of Node. Node type is determined automatically when
* [<][] method is called.
* Each Node implementation knows its own type and delegates the call to the corresponding
* Visitor's method.
*/
interface NodeVisitor<U> {
/**
* Called when accepting Node is Company
*/
fun visit(company: Company?, data: U): U
/**
* Called when accepting Node is BusinessEntity
*/
fun visit(businessEntity: BusinessEntity?, data: U): U
/**
* Called when accepting Node is Team
*/
fun visit(team: Team?, data: U): U
/**
* Called when accepting Node is Member
*/
fun visit(member: Member?, data: U): U
}
class Company(override var name: String) : Node {
private var businessEntities: MutableList<BusinessEntity> = ArrayList()
fun businessEntity(businessEntity: BusinessEntity): Company {
businessEntities.add(businessEntity)
return this
}
fun getBusinessEntities(): List<BusinessEntity> {
return businessEntities
}
override val children: List<Node>
get() = getBusinessEntities()
override fun <U> accept(data: U, visitor: NodeVisitor<U>): U {
// double-dispatch to the custom method for Company nodes
return visitor.visit(this, data)
}
}
class BusinessEntity(override var name: String) : Node {
private var teams: MutableList<Team> = ArrayList()
fun team(team: Team): BusinessEntity {
teams.add(team)
return this
}
fun getTeams(): List<Team> {
return teams
}
override val children: List<Node>
get() = getTeams()
override fun <U> accept(data: U, visitor: NodeVisitor<U>): U {
// double-dispatch to the custom method for BusinessEntity nodes
return visitor.visit(this, data)
}
}
class Team(override var name: String) : Node {
private var members: MutableList<Member> = ArrayList()
fun member(member: Member): Team {
members.add(member)
return this
}
fun getMembers(): List<Member> {
return members
}
override val children: List<Node>
get() = getMembers()
override fun <U> accept(data: U, visitor: NodeVisitor<U>): U {
// double-dispatch to the custom method for Team nodes
return visitor.visit(this, data)
}
}
class Member(override var name: String) : Node {
override val children: List<Node>
get() = emptyList()
override fun <U> accept(data: U, visitor: NodeVisitor<U>): U {
// double-dispatch to the custom method for Member nodes
return visitor.visit(this, data)
}
}