Services exposed by a hierarchical data model are node specific.Using those can be dynamic using type switches in Go, without scarifying simplicity. Each level is implemented by a set of interfaces which are grouped in a type switch.Further, type switches for all levels can be nested. Keeping separate type switch for each level improves code readability
To start with, consider below diagram :
Each level in model is implemented by specific set of interfaces.(Each node is has interface in this example):
Interface set for Root :
type RootInterface interface{
RootFunc()
}
Interface set for Level One :
type L1c1 interface{//Level One Child one.
L1c1Func()
}
Interface set for Level two :
type L1c2 interface{
L1c2Func()
}
type L1c3 interface{
L1c3Func()
}
Interface set for Level Three :
type L2c1 interface { //Level Two Child one.
L2c1Func()
}
type L2c2 interface {
L2c2Func()
}
type L2c3 interface {
L2c3Func()
}
type L2c4 interface {
L2c4Func()
}
Now a concrete type for a node ,which implements hierarchy interfaces
type CHildC4 struct{}
//Root->L1c1->L2c1
var p = fmt.Println
func (v CHildC4) RootFunc() {
p("Root is satisfied")
}
func (v CHildC4) L1c1Func() {
p("Level 1 is satisfied")
}
func (v CHildC4) L2c1Func() {
p("level 2 is satisfied")
}
In main type switches for each level in hierarchy.Here switches are not nested.
Note : No fall through is allowed in type switches
func main() {
var input interface{}
input = CHildC4{}
//Switch for root level :
switch t := input.(type) {
case RootInterface:
t.RootFunc()
default:
fmt.Println("No Root!!") //Error Handling
return
}
//Switch for first level :
switch t := input.(type) {
case L1c1:
t.L1c1Func()
case L1c2:
t.L1c2Func()
case L1c3:
t.L1c3Func()
default:
fmt.Println("No Level 1!!") //Error Handling
return
}
//Switch for second level level :
switch t := input.(type) {
case L2c1:
t.L2c1Func()
case L2c2:
t.L2c2Func()
case L2c3:
t.L2c3Func()
default:
fmt.Println("No Level 2!!") //Error Handling
return
}
}