This commit is contained in:
leisore
2015-08-12 11:41:01 +08:00
parent 1e467cfb71
commit 0d5fb59871
2 changed files with 140 additions and 1 deletions

View File

@@ -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具有更大的灵活性。
下面的模式就很好的说明了这个问题:
![](images/10.6.9_fig10.4.jpg?raw=true)
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) - [目录](directory.md)

Binary file not shown.

After

Width:  |  Height:  |  Size: 42 KiB