前言
用过OOP
的都知道,子类重写父类的方法可以优雅的实现代码的复用,例如:
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
| public abstract class People { String name; int age;
public People(String name, int age) { this.name = name; this.age = age; }
public void hello() { System.out.printf("name:%s age:%d sex:%s\n", name, age, sex()); }
public abstract String sex();
static class Male extends People {
public Male(String name, int age) { super(name, age); }
@Override public String sex() { return "M"; } }
static class Female extends People {
public Female(String name, int age) { super(name, age); }
@Override public String sex() { return "F"; } }
public static void main(String[] args) { new Male("小明",20).hello(); new Female("小红",18).hello(); } }
|
输出:
1 2
| name:小明 age:20 sex:M name:小红 age:18 sex:F
|
但是go
不支持OOP
,那么在go
中要类似情况的应该怎么实现?
错误的示范
一开始我想通过go
提供的组合模拟继承来实现,于是有了以下代码:
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
| package main
import ( "fmt" )
type People struct { name string age int }
func (p *People) say() { fmt.Printf("name:%s age:%d sex:%s\n", p.name, p.age, p.sex()) }
func (p *People) sex() string { return "unknown" }
type Male struct { People }
func (m *Male) sex() string { return "M" }
type Female struct { People }
func (f *Female) sex() string { return "F" }
func main() { m := &Male{People{name: "小明", age: 20}} m.say() f := &Female{People{name: "小红", age: 18}} f.say() }
|
上面代码中分别Male
和Female
都重写了sex()
方法,来进行方法重用,然而运行的结果却和预料的不一样,输出:
1 2
| name:小明 age:20 sex:unknown name:小红 age:18 sex:unknown
|
从输出结果可以看到,依旧是调用的people结构体的sex方法
,因为go
并不支持OOP
,组合类型其实只是某种形式上的语法弹,并不会改变"父类"
中调用的方法。
通过接口实现
抽象一个Sex
接口出来,由Male
和Female
来具体实现,直接上代码:
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
| package main
import ( "fmt" )
type Sex interface { sex() string }
type People struct { name string age int Sex }
func (p *People) say() { fmt.Printf("name:%s age:%d sex:%s\n", p.name, p.age, p.sex()) }
type Male struct { }
func (m *Male) sex() string { return "M" }
func (m *Male) play(){ fmt.Println("男生爱打游戏") }
type Female struct { }
func (f *Female) sex() string { return "F" }
func (f *Female) sing() { fmt.Println("女生爱唱歌") }
func main() { m := &People{name: "小明", age: 20, Sex: &Male{}} m.say() f := &People{name: "小红", age: 18, Sex: &Female{}} f.say() }
|
输出:
1 2
| name:小明 age:20 sex:M name:小红 age:18 sex:F
|
不过这样也引入了一个新的问题,m
和f
变量都是People
类型,比如现在有个方法需要通过性别来做不同的处理,那么就要使用类型断言
来实现了,例如:
1 2 3 4 5 6 7 8 9 10
| func handle(people *People){ switch sex := people.Sex.(type) { case *Male: sex.play() case *Female: sex.sing() default: panic("error") } }
|