Aturan dari Dependency Inversion Principle (DIP) adalah
- Modul Level Atas tidak boleh bergantung pada modul level bawah
- Kedua modul tersebut harus bergantung pada abstraction
Berikut contoh kode yang melanggar DIP. Dimana fungsi research (dalam hal ini adalah high level modul), tergantung pada Relationships struct (low level modul).
Untuk kondisi saat ini, kode memang berfungsi dengan baik, namun ketika Relationship struct diubah menjadi model storage lain, yang bukan berupa slice. Kode pada fungsi research akan error.
package main
import "fmt"
type Relationship int
const (
Parent Relationship = iota
Child
Sibling
)
type Person struct {
name string
// other useful stuff here
}
type Info struct {
from *Person
relationship Relationship
to *Person
}
type Relationships struct {
relations []Info
}
type Research struct {
relationships Relationships
}
func (rs *Relationships) AddParentAndChild(parent, child *Person) {
rs.relations = append(rs.relations,
Info{parent, Parent, child})
rs.relations = append(rs.relations,
Info{child, Child, parent})
}
func (r *Research) Investigate() {
relations := r.relationships.relations
for _, rel := range relations {
if rel.from.name == "John" &&
rel.relationship == Parent {
fmt.Println("John has a child called", rel.to.name)
}
}
}
func main() {
parent := Person{"John"}
child1 := Person{"Chris"}
child2 := Person{"Matt"}
// low-level module
relationships := Relationships{}
relationships.AddParentAndChild(&parent, &child1)
relationships.AddParentAndChild(&parent, &child2)
research := Research{relationships}
research.Investigate()
}
Agar tidak melanggar prinisp DIP, diperlukan abstraction yang menghubungkan high level modul dengan low level modul. Dimana abstraction akan berisi kode yang mengakses low level modul.
type RelationshipBrowser interface {
FindAllChildrenOf(name string) []*Person
}
func (rs *Relationships) FindAllChildrenOf(name string) []*Person {
result := make([]*Person, 0)
for i, v := range rs.relations {
if v.relationship == Parent &&
v.from.name == name {
result = append(result, rs.relations[i].to)
}
}
return result
}
Pada high level modul, cukup menggunakan abstraction diatas untuk mengakses low level modul.
type Research struct {
browser RelationshipBrowser // low-level
}
Berikut kode lengkap yang mengikuti prinsip DIP.
package main
import "fmt"
type Relationship int
const (
Parent Relationship = iota
Child
Sibling
)
type Person struct {
name string
// other useful stuff here
}
type Info struct {
from *Person
relationship Relationship
to *Person
}
type RelationshipBrowser interface {
FindAllChildrenOf(name string) []*Person
}
type Relationships struct {
relations []Info
}
func (rs *Relationships) FindAllChildrenOf(name string) []*Person {
result := make([]*Person, 0)
for i, v := range rs.relations {
if v.relationship == Parent &&
v.from.name == name {
result = append(result, rs.relations[i].to)
}
}
return result
}
func (rs *Relationships) AddParentAndChild(parent, child *Person) {
rs.relations = append(rs.relations,
Info{parent, Parent, child})
rs.relations = append(rs.relations,
Info{child, Child, parent})
}
type Research struct {
browser RelationshipBrowser // low-level
}
func (r *Research) Investigate() {
for _, p := range r.browser.FindAllChildrenOf("John") {
fmt.Println("John has a child called", p.name)
}
}
func main() {
parent := Person{"John" }
child1 := Person{ "Chris" }
child2 := Person{ "Matt" }
// low-level module
relationships := Relationships{}
relationships.AddParentAndChild(&parent, &child1)
relationships.AddParentAndChild(&parent, &child2)
research := Research{&relationships}
research.Investigate()
}
1 thought on “SOLID: Dependency Inversion Principle”