空对象设计模式是一种行为型设计模式,主要用于应对空对象的检查。使用这种设计模式可以避免对空对象进行检查。也就是说,在这种模式下,使用空对象不会造成异常。
空对象模式的组件包括:
- Entity:接口,定义了子struct需要实现的方法
- ConcreteEntity:实现了Entity 的具体struct
- NullEntity:这个就表示了空对象,虽然也实现了Entity接口,但它的值都是空的
- Client:这个类会获取Entity接口实现类的实例并使用它。这里并不关注实现类是
ConcreteEntity
还是NullEntity
,对二者会进行相同的处理。
用个例子来说一下:假设有一所大学,大学有多个系,每个系都有一定数量的教授。
系(department)可以用一个接口来表示:
type department interface {
getNumberOfProfessors() int getName() string
}
大学(college)也是一个接口:
type college struct {
departments []department
}
现在假设有一个机构想统计下大学每个系的教授数量。
在这个例子里,假设大学里没有某个系,我们就会用到空对象模式。这里定义了一个nullDepartment
来表示不存在的系。
nullDepartment.go:
type nullDepartment struct {
numberOfProfessors int
} func (c *nullDepartment) getNumberOfProfessors() int {
return 0
} func (c *nullDepartment) getName() string {
return "nullDepartment"
}
统计的代码在agency.go里:
func main() {
college1 := createCollege1()
college2 := createCollege2()
totalProfessors := 0
departmentArray := []string{"computerScience", "mechanical", "civil", "electronics"} for _, departmentName := range departmentArray {
d := college1.getDepartment(departmentName)
totalProfessors += d.getNumberOfProfessors()
} fmt.Printf("Total number of professors in college1 is %d\n", totalProfessors) //Reset the professor count
totalProfessors = 0
for _, departmentName := range departmentArray {
d := college2.getDepartment(departmentName)
totalProfessors += d.getNumberOfProfessors()
}
fmt.Printf("Total number of professors in college2 is %d\n", totalProfessors)
} func createCollege1() *college {
college := &college{}
college.addDepartment("computerScience", 4)
college.addDepartment("mechanical", 5)
return college
} func createCollege2() *college {
college := &college{}
college.addDepartment("computerScience", 2)
return college
}
注意这段代码:
- agency.go 并不关心某个系在大学里是否存在。当这个系不存在时,大学只需要返回一个
nullDepartment
对象即可 - agency.go 对
nullDepartment
对象和其他department
实现类的对象做了相同处理,这之中不需要对空值进行检查,直接调用getNumberOfProfessors()
就可以了
以上就是使用空对象模式的好处了。
下面是其他的代码。
college.go:
type college struct {
departments []department
} func (c *college) addDepartment(departmentName string, numOfProfessors int) {
if departmentName == "computerScience" {
computerScienceDepartment := &computerScience{numberOfProfessors: numOfProfessors}
c.departments = append(c.departments, computerScienceDepartment)
}
if departmentName == "mechanical" {
mechanicalDepartment := &mechanical{numberOfProfessors: numOfProfessors}
c.departments = append(c.departments, mechanicalDepartment)
}
return
} func (c *college) getDepartment(departmentName string) department {
for _, department := range c.departments {
if department.getName() == departmentName {
return department
}
}
//Return a null department if the department doesn't exits
return &nullDepartment{}
}
计算机系,computerscience.go:
type computerScience struct {
numberOfProfessors int
} func (c *computerScience) getNumberOfProfessors() int {
return c.numberOfProfessors
} func (c *computerScience) getName() string {
return "computerScience"
}
数学系,mechanical.go:
type mechanical struct {
numberOfProfessors int
} func (c *mechanical) getNumberOfProfessors() int {
return c.numberOfProfessors
} func (c *mechanical) getName() string {
return "mechanical"
}
执行agency.go,输出内容如下:
Total number of professors in college1 is 9
Total number of professors in college2 is 2
End!!