1.没有使用开闭原则的代码
package main
import "fmt"
type phone struct {
host string
}
func (p *phone) photo() {
fmt.Printf("%s", "这是"+p.host+"手机的拍照功能\n")
}
func (p *phone) sendInfo() {
fmt.Printf("%s", "这是"+p.host+"手机的发短信功能\n")
}
func main() {
p1 := phone{host: "xhz"}
p1.photo()
}
- 假设现在根据需求,手机加入听音乐的功能,手机要存下音乐名字
- 这时候就一定会涉及到,在原来结构体里面
加上新字段 musicName string,类似于下面这样
type phone struct {
host string
musicName string
}
func (p *phone) listenMusic() {
fmt.Printf("%s %s", "这是"+p.host+"手机的听音乐功能,听曲子--", p.musicName+"\n")
}
package main
import "fmt"
type phone struct {
host string
musicName string
}
func (p *phone) photo() {
fmt.Printf("%s", "这是"+p.host+"手机的拍照功能\n")
}
func (p *phone) sendInfo() {
fmt.Printf("%s", "这是"+p.host+"手机的发短信功能\n")
}
func (p *phone) listenMusic() {
fmt.Printf("%s %s", "这是"+p.host+"手机的听音乐功能,听曲子--", p.musicName+"\n")
}
func main() {
p1 := phone{host: "xhz"}
p1.photo()
p2 := phone{host: "xhz", musicName: "我爱你中国"}
p2.listenMusic()
}
缺点:涉及到变量的增加的时候,势必引起原结构体设计的改动
这种就很不符合"开闭原则"
2.使用开闭原则的代码
- 既然不能动原来结构体的源代码,那么就只能把新字段 musicName 放进一个新的结构体
但用新的结构体绑定新的【听音乐功能】显然已经不符合要求- 因为这样就相当于新的结构体,有了自己的第一个功能
为了还是让【听音乐功能】和以前的功能
形成同级关系,那就引入接口,把发短信,拍照抽象成一个work( )功能,原本函数名就能看出功能的事情就交给结构体名来体现,类似于下面这样:
type tool interface {
work()
}
type photoPhone struct {
name string
}
func (p *photoPhone) work() {
fmt.Printf("%s", "这是"+p.name+"手机的拍照功能\n")
}
type sendInfoPhone struct {
name string
}
func (s *sendInfoPhone) work() {
fmt.Printf("%s", "这是"+s.name+"手机的发短信功能\n")
}
再有什么新的功能,那就再写一个新的结构体,实现work( ),这就是开闭原则(OCP)
开闭原则: 增加功能(涉及到新字段)不是通过改原来结构体解决的,而是写新结构体解决的
type listenMusicPhone struct {
name string
musicName string
}
// 当然还可以进一步提炼出一个基于接口层封装的函数,因为现在大家都实现了work()函数嘛
func (l *listenMusicPhone) work() {
fmt.Printf("%s %s", "这是"+l.name+"手机的听音乐功能,听曲子--", l.musicName+"\n")
}
// 就像这样
func allTools(t tool) {
t.work()
}
所以完整的 开闭原则设计代码
package main
import "fmt"
type tool interface {
work()
}
type photoPhone struct {
name string
}
func (p *photoPhone) work() {
fmt.Printf("%s", "这是"+p.name+"手机的拍照功能\n")
}
type sendInfoPhone struct {
name string
}
func (s *sendInfoPhone) work() {
fmt.Printf("%s", "这是"+s.name+"手机的发短信功能\n")
}
type listenMusicPhone struct {
name string
musicName string
}
func (l *listenMusicPhone) work() {
fmt.Printf("%s %s", "这是"+l.name+"手机的听音乐功能,听曲子--", l.musicName+"\n")
}
func allTools(t tool) {
t.work()
}
func main() {
p := photoPhone{name: "xhz"}
p.work()
allTools(&p)
s := sendInfoPhone{name: "xhz"}
s.work()
allTools(&s)
l := listenMusicPhone{name: "xhz", musicName: "我爱你中国"}
l.work()
allTools(&l)
}
总结:
要想做到开闭原则,那么就必须让函数放进接口里
因为只有这样才能让新的结构体实现函数的时候达到自定义的效果