mirror of
https://github.com/unknwon/the-way-to-go_ZH_CN.git
synced 2025-08-12 04:48:29 +08:00
10.6 OK
This commit is contained in:
141
eBook/10.6.md
141
eBook/10.6.md
@@ -526,7 +526,146 @@ func (c *Customer) String() string {
|
||||
|
||||
因此一个好的策略是创建一些小的、可复用的类型作为一个工具箱,用于组成域类型。
|
||||
|
||||
** 10.6.7 多根继承
|
||||
** 10.6.7 多重继承
|
||||
|
||||
多重继承指的是类型获得多个父类型行为的能力,它在传统的面向对象语言中通常是不被实现的(C++和Python例外)。因为在类继承层次中,多重继承会给编译器引入额外的复杂度。但是Go语言中,通过在类型中嵌入所有必要的父类型,可以很简单的实现多重继承。
|
||||
|
||||
作为一个例子,假设有一个类型CameraPhone,通过它可以Call(),也可以TakeAPicture(),但是第一个方法属于类型Phone,第二个方法属于类型Camera。
|
||||
|
||||
只要嵌入这两个类型就可以解个问题,如下所示:
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
)
|
||||
|
||||
type Camera struct{}
|
||||
|
||||
func (c *Camera) TakeAPicture() string {
|
||||
return "Click"
|
||||
}
|
||||
|
||||
type Phone struct{}
|
||||
|
||||
func (p *Phone) Call() string {
|
||||
return "Ring Ring"
|
||||
}
|
||||
|
||||
type CameraPhone struct {
|
||||
Camera
|
||||
Phone
|
||||
}
|
||||
|
||||
func main() {
|
||||
cp := new(CameraPhone)
|
||||
fmt.Println("Our new CameraPhone exhibits multiple behaviors...")
|
||||
fmt.Println("It exhibits behavior of a Camera: ", cp.TakeAPicture())
|
||||
fmt.Println("It works like a Phone too: ", cp.Call())
|
||||
}
|
||||
```
|
||||
|
||||
输出:
|
||||
|
||||
Our new CameraPhone exhibits multiple behaviors...
|
||||
It exhibits behavior of a Camera: Click
|
||||
It works like a Phone too: Ring Ring
|
||||
|
||||
* 练习 10.9:* point_methods.go:
|
||||
|
||||
从point.go开始(10.1的联系):使用方法来实现Abs()和Scale()函数,Point作为方法的接收者类型。也为Point3和Polar实现Abs()方法。做point.go中同样的事情,只是这次通过方法。
|
||||
|
||||
* 练习 10.10:* inherit_methods.go:
|
||||
|
||||
定义一个结构体类型Base,它包含一个字段id,方法Id()返回id,方法SetId()修改id。结构体类型Person包含Base,及FirstName和LastName字段。结构体类型Employee包含一个Person和salary字段。
|
||||
|
||||
创建一个employee实例,然后显示它的id。
|
||||
|
||||
* 练习 10.11:* magic.go:
|
||||
|
||||
首先预测一下下面程序的结果,然后动手实验下:
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
)
|
||||
|
||||
type Base struct{}
|
||||
|
||||
func (Base) Magic() {
|
||||
fmt.Println("base magic")
|
||||
}
|
||||
|
||||
func (self Base) MoreMagic() {
|
||||
self.Magic()
|
||||
self.Magic()
|
||||
}
|
||||
|
||||
type Voodoo struct {
|
||||
Base
|
||||
}
|
||||
|
||||
func (Voodoo) Magic() {
|
||||
fmt.Println("voodoo magic")
|
||||
}
|
||||
|
||||
func main() {
|
||||
v := new(Voodoo)
|
||||
v.Magic()
|
||||
v.MoreMagic()
|
||||
}
|
||||
```
|
||||
|
||||
** 10.6.8 通用方法和方法命名
|
||||
|
||||
在编程中一些基本操作会一遍又一遍的出现,比如打开(Open)、关闭(Close)、读(Read)、写(Write)、排序(Sort)等等,并且它们都有一个大致的意思:打开(Open)可以作用于一个文件、一个网络连接、一个数据库连接等等。具体的实现可能千差万别,但是基本的概念是一致的。在Go语言中,通过使用接口(参考 第11章),标准库广泛的应用了这些规则,在标准库中这些通用方法都有一致的名字,比如Open()、Read()、Write()等。想写规范的Go程序,就应该遵守这些约定,给方法合适的名字和签名,就像那些通用方法那样。这样做会使Go开发的软件更加具有一致性和可读性。比如:如果需要一个convert-to-string方法,应该命名为String(),而不是ToString()(参考10.7).
|
||||
|
||||
** 10.6.9 和其他面向对象语言比较Go的类型和方法
|
||||
|
||||
在如C++、Java、C#和Ruby这样的面向对象语言中,方法在类的上下文中被定义和继承:在一个对象上调用方法时,运行时会检测类以及它的超类中是否有此方法的定义,如果没有会导致异常发生。
|
||||
|
||||
在Go中,这样的继承层次是完全没必要的:如果方法在此类型定义了,就可以调用它,和其他类型上是否存在这个方法没有关系。在这个意义上,Go具有更大的灵活性。
|
||||
|
||||
下面的模式就很好的说明了这个问题:
|
||||
|
||||

|
||||
|
||||
Go不需要一个显式的类定义,如同Java、C++、C#等那样,相反地,,“类”是通过提供一组作用于一个共同类型的方法集来隐式定义的。类型可以是结构体或者任何用户自定义类型。
|
||||
|
||||
比如:我们想定义自己的Integer类型,并添加一些类似转换成字符串的方法,在Go中可以如下定义:
|
||||
|
||||
```go
|
||||
type Integer int
|
||||
func (i *Integer) String() string {
|
||||
return strconv.Itoa(i)
|
||||
}
|
||||
```
|
||||
|
||||
在Java或C#中,这个方法需要和类Integer的定义放在一起,在Ruby中可以直接在基本类型int上定义这个方法。
|
||||
|
||||
*总结*:
|
||||
|
||||
在Go中,类型就是类(数据和关联的方法)。Go不知道类似OO语言的类继承的概念。继承有两个好处:代码复用和多态。
|
||||
|
||||
在Go中,代码复用通过组合和委托实现,多态通过接口的使用来实现:有时这也叫*组件编程*。
|
||||
|
||||
许多开发者说相比于类继承,Go的接口提供了更强大、却更简单的多态行为。
|
||||
|
||||
*备注*:
|
||||
|
||||
如果真的需要更多OO的能力,看一下goop包(Go Object-Oriented Programming),它来自与Scott Pakin[(https://github.com/losalamos/goop]: 它给Go提供了JavaScript风格的对象(基于原型的对象),并且支持多重继承和类型独立分派,通过它可以实现你喜欢的其他编程语言里的一些结构。
|
||||
|
||||
** 问题 10.1:
|
||||
我们在某个类型的变量上使用点号调用一个方法:variable.method(),在使用Go以前,在哪儿碰到过OO的点号?
|
||||
|
||||
** 问题 10.2:
|
||||
|
||||
a) 假设定义: `type Integer int`,完成get()方法的方法体: `func (p Integer) get() int { ... }`
|
||||
b) 定义: `func f(i int) {}; var v Integer` , 如何就v作为参数调用f?
|
||||
c) 假设Integer定义为:`type Integer struct {n int}`,完成get()方法的方法体:`func (p Integer) get() int { ... }`
|
||||
d) 对于新定义的Integer,和b)中同样的问题
|
||||
|
||||
## 链接
|
||||
- [目录](directory.md)
|
||||
|
BIN
eBook/images/10.6.9_fig10.4.jpg
Normal file
BIN
eBook/images/10.6.9_fig10.4.jpg
Normal file
Binary file not shown.
After Width: | Height: | Size: 42 KiB |
Reference in New Issue
Block a user