转自:http://blog.csdn.net/yue7603835/article/details/44282823

Go语言的面向对象编程简单而干净,通过非侵入式接口模型,否定了C/C++ Java C#等传统面向对象编程语言的复杂度的必要性,我们发现在Go中即使简单的组合也能达到传统面向对象语言的效果,而且耦合度非常低,按照Go的作者之一也就是C语言的作者之一说的一句话:Go是更好的C语言。
1、Go中任意类型Any即  interface{}类型,也就是空接口,可以赋值为任意类型
2、可以为其他类型 内置类型 不包括指针类型添加相应的方法 但是注意的一点是一定要用别名。。进行包装
记住想要 为类型 添加新的方法 那么请把类型定义别名,别名和原来的类型就不一样了成了新类型  
在Go中只能对非本地类型添加方法......也就是int不能添加方法 需要 type Int int 才可以为Int添加方法
package main
import(
"fmt"
)
type Integer int
func (a Integer) Less(b Integer)bool {
return a<b
}
func main(){
var a Integer=
r:=a.Less()
fmt.Println(r)
}
/////用法2 组合之指针
package main
import(
"fmt"
)
type Integer int
func (a *Integer) Less(b Integer)bool {
*a-=
return *a<b
} type Int int
func (a *Int) LessIne(b Int)bool{
return *a<b
}
func main(){
var a Integer=
var aa int=
a=Integer(aa)
r:=a.Less()
fmt.Println(r)
}
 
3、go中不存在this指针,通过语法糖显式传递对象
在Go语言中没有隐藏的this指针”这句话的含义是:
 方法施加的目标(也就是“对象” )显式传递,没有被隐藏起来;
 方法施加的目标(也就是“对象” )不需要非得是指针,也不用非得叫this。 
4、用type定以后的别名类型就是新类型了 只有强制转换才能使用
package main
import(
"fmt"
)
type Integer int
func (a Integer) Less(b Integer)bool {
return a<b
}
func main(){
var a Integer=
var aa int=
a=Integer(aa) //不强制转换会编译出错的
r:=a.Less()
fmt.Println(r)
}
5、Go中的值语义和引用   
channel map本质是指针 因为复制他们没有意义  ........数组切片 []type 本质上是值类型 interface接口非常重要
值语义和引用语义的差别在于赋值,比如下面的例子:
b = a
b.Modify()
如果b的修改不会影响a的值,那么此类型属于值类型。如果会影响a的值,那么此类型是引用
类型。
Go语言中的大多数类型都基于值语义,包括:
 基本类型,如byte、int、bool、float32、float64和string等;
 复合类型,如数组(array) 、结构体(struct)和指针(pointer)等。
Go语言中类型的值语义表现得非常彻底。我们之所以这么说,是因为数组。
如果读者之前学过C语言,就会知道C语言中的数组比较特别。通过函数传递一个数组的时
候基于引用语义, 但是在结构体中定义数组变量的时候基于值语义 (表现在为结构体赋值的时候,
该数组会被完整地复制) 。
Go语言中的数组和基本类型没有区别,是很纯粹的值类型,例如:
var a = []int{, , }
var b = a
b[]++
fmt.Println(a, b)
该程序的运行结果如下:
[1 2 3] [1 3 3]。
这表明b=a赋值语句是数组内容的完整复制。要想表达引用,需要用指针:
var a = []int{, , }
var b = &a
b[]++
fmt.Println(a, *b)
该程序的运行结果如下:
[1 3 3] [1 3 3]
这表明b=&a赋值语句是数组内容的引用。变量b的类型不是[3]int,而是*[3]int类型。
Go语言中有4个类型比较特别,看起来像引用类型,如下所示
 
数组切片:指向数组(array)的一个区间。
 map:极其常见的数据结构,提供键值查询能力。
 channel:执行体(goroutine)间的通信设施。
 接口(interface) :对一组满足某个契约的类型的抽象。
但是这并不影响我们将Go语言类型看做值语义。下面我们来看看这4个类型。
数组切片本质上是一个区间,你可以大致将[]T表示为:
type slice struct {
first *T
len int
cap int
}
因为数组切片内部是指向数组的指针,所以可以改变所指向的数组元素并不奇怪。数组切片
类型本身的赋值仍然是值语义。
map本质上是一个字典指针,你可以大致将map[K]V表示为:
type Map_K_V struct {

// ...
} type map[K]V struct {
impl *Map_K_V
}
基于指针,我们完全可以自定义一个引用类型,如:
type IntegerRef struct {
impl *int
}
channel和map类似,本质上是一个指针。将它们设计为引用类型而不是统一的值类型的原因
是,完整复制一个channel或map并不是常规需求。
同样,接口具备引用语义,是因为内部维持了两个指针,示意为:
type interface struct {
data *void
itab *Itab
}
接口在Go语言中的地位非常重要。关于接口的内部实现细节,在后面的高阶话题中我们再
细细剖析。 
7、Go语言中的结构体  组合非继承
Go语言的结构体(struct)和其他语言的类(class)有同等的地位,但Go语言放弃了包括继
承在内的大量面向对象特性,只保留了组合(composition)这个最基础的特性。
组合甚至不能算面向对象特性,因为在C语言这样的过程式编程语言中,也有结构体,也有
组合。组合只是形成复合类型的基础。
上面我们说到,所有的Go语言类型(指针类型除外)都可以有自己的方法。在这个背景下,
Go语言的结构体只是很普通的复合类型,平淡无奇。例如,我们要定义一个矩形类型:
type Rect struct {
x, y float64
width, height float64
}
然后我们定义成员方法Area()来计算矩形的面积:
func (r *Rect) Area() float64 {
return r.width * r.height
}
可以看出, Go语言中结构体的使用方式与C语言并没有明显不同。 
8、Go中的组合精华  创建结构体指针 和为 结构体扩充成员函数的时候.....传递 值类型和指针类型的区别
package main
import "fmt"
type Rect struct{
x,y float64
width,height float64
}
///如果写成rct Rect 那么内部的修改不会影响到 外部结构
///如果写成rct*Rect那么内部的修改会影响到外部结构的值 这就是 指针的效果
func (rct *Rect)Area() float64{
rct.width= ///也可以(*rct).width=1000一样
return rct.width*rct.height
}
func main(){
rct:=new(Rect)
//对于结构体指针,...调用方法和值类型一样直接.唯一的区别是 作为参数传递的时候 传递的是地址 值可以被修改
//所以进行组合的时候就有两种选择
// 可以写成 var rct*Rect=&Rect{}
//也可以写成 var rct Rect=Rect{}
//var rct *Rect=new(Rect)
//也可以写成 var rct Rect=Rect{1,2,3,4}
rct.width=10.0
rct.height=10.0
area:=rct.Area()
fmt.Println(area)
fmt.Println(rct.width)
}
 
 
9、普通的组合继承 ...........................以及组合指针继承 以及覆盖 和函数 成员名字冲突 
//通过值类型继承
package main
import "fmt"
//Go中继承属于匿名组合 .......可以从对象继承 也可以从指针匿名继承...
//匿名继承会去掉包名,,,所以不能同时继承类名相同的 即使不在同一个包中
type Base struct{
Name string
Age uint8
}
///为Base结构体组合进去两个函数
func (pBase*Base) showName(){
fmt.Println("Age",pBase.Name)
}
func (pBase*Base) showAge(){
fmt.Println("Age",pBase.Age)
}
//创建Sub结构体
type Sub struct{
//组合Base修改内存模型
//匿名组合进Base 对于调用者是不知道的
//即使我们覆盖了 Base的方法 但是我们还是可以通过xxx.Base.xxx()调用基类的方法的
//如果是*Base我们需要在调用处手动添加new Base 否则运行会出错的
Base
}
func (pSub*Sub) showName(){
fmt.Println("Before Sub ShowName")
pSub.Base.showName()
fmt.Println("After Sub ShowName")
}
func main(){
obj:=new(Sub)
obj.Name="张三"
obj.Age=
obj.showName()
obj.showAge()
}
///通过指针类型继承
package main
import "fmt"
//Go中继承属于匿名组合 .......可以从对象继承 也可以从指针匿名继承...
//匿名继承会去掉包名,,,所以不能同时继承类名相同的 即使不在同一个包中
type Base struct{
Name string
Age uint8
}
///为Base结构体组合进去两个函数
func (pBase*Base) showName(){
fmt.Println("Age",pBase.Name)
}
func (pBase*Base) showAge(){
fmt.Println("Age",pBase.Age)
}
//创建Sub结构体
type Sub struct{
//组合Base修改内存模型
//匿名组合进Base 对于调用者是不知道的
//即使我们覆盖了 Base的方法 但是我们还是可以通过xxx.Base.xxx()调用基类的方法的
*Base
}
func (pSub*Sub) showName(){
fmt.Println("Before Sub ShowName")
pSub.Base.showName()
fmt.Println("After Sub ShowName")
}
func main(){
obj:=new(Sub)
//由于使用指针继承所以 我们要设置匿名组合模板的内存对象 地址
obj.Base=&Base{}
obj.Name="张三"
obj.Age=
obj.showName()
obj.showAge()
}
 
10、Go语言的可见性 权限是包一级的,包外的不能访问包内的小写开头成员......包内无所谓
 
11、Go的非侵入式接口 和实现     
/////Go语言会为每一个成员函数 自动生成对应的函数  比如 func(a *A) 会自动生成 func (a A) .....
///反过来则不行 因为 func (a A)这时候传递的是形参 (&a).xx()改变的是 参数 副本 而不是 外部类
package main
import "fmt"
///非侵入式接口
////接口 和实现完全分析 减少耦合
///实现方只负责实现 接口方只负责封装自己的借口就行...实现方甚至不知道 有这个接口的存在 这就是 Go的 非侵入式接口的特点
type IFly interface{
fly()
}
type ISay interface{
say()
}
type Bird struct{ }
//由于匿名传递进来的是指针类型 所对于接口的赋值必须是 指针
func (pBird*Bird) fly(){
fmt.Println("i am a bird, i can fly()!")
}
//由于匿名传递的不是指针类型是值类型 所以接口赋值 可以不是指针而是值
func (pBird Bird) say(){
fmt.Println("i am a bird, i can say()!")
}
func main(){
birdObj:=Bird{} var iFly IFly=&birdObj
iFly.fly()
var iSay ISay=birdObj
iSay.say()
}
13、接口之间是可以相互赋值的
实现了相同方法的接口可以相互赋值,如果接口B是A非超集,那么  A可以赋值为B
对象不可以被赋值为接口 ,繁殖接口可以被赋值为实现了 某些方法的对象 或者包含他方法的 接口对象
package main
import "fmt"
///非侵入式接口
////接口 和实现完全分析 减少耦合
///实现方只负责实现 接口方只负责封装自己的借口就行...实现方甚至不知道 有这个接口的存在 这就是 Go的 非侵入式接口的特点
type IFly interface{
fly()
}
type ISay interface{
say()
}
type IFly1 interface{
fly()
}
type ISay1 interface{
say()
}
type Bird struct{ }
//由于匿名传递进来的是指针类型 所对于接口的赋值必须是 指针
func (pBird*Bird) fly(){
fmt.Println("i am a bird, i can fly()!")
}
//由于匿名传递的不是指针类型是值类型 所以接口赋值 可以不是指针而是值
func (pBird Bird) say(){
fmt.Println("i am a bird, i can say()!")
}
func main(){
birdObj:=Bird{} var iFly IFly=&birdObj
iFly.fly()
var iSay ISay=birdObj
iSay.say()
////接口之间的赋值
var iFly1 IFly1=iFly
iFly1.fly()
}
14、Go中的值类型非常的彻底  数组都是值类型
 
15、关于给类型添加String()方法   相当于 其他语言的toString 用于打印输出
package main
import "fmt"
///非侵入式接口
////接口 和实现完全分析 减少耦合
///实现方只负责实现 接口方只负责封装自己的借口就行...实现方甚至不知道 有这个接口的存在 这就是 Go的 非侵入式接口的特点
type IFly interface{
fly()
}
type ISay interface{
say()
}
type IFly1 interface{
fly()
}
type ISay1 interface{
say()
}
type Bird struct{ }
//由于匿名传递进来的是指针类型 所对于接口的赋值必须是 指针
func (pBird*Bird) fly(){
fmt.Println("i am a bird, i can fly()!")
}
//由于匿名传递的不是指针类型是值类型 所以接口赋值 可以不是指针而是值
func (pBird Bird) say(){
fmt.Println("i am a bird, i can say()!")
}
func (pBird Bird) String() string{
return "aaaaaaaaaa"
}
func main(){
birdObj:=Bird{} var iFly IFly=&birdObj
iFly.fly()
var iSay ISay=birdObj
iSay.say()
////接口之间的赋值
var iFly1 IFly1=iFly
iFly1.fly()
fmt.Println(birdObj)
}
16、接口的组合 就是把多个接口组合到一起......接口中只有函数没有属性
type IFly interface{
fly()
}
type ISay interface{
say()
}
type IFly1 interface{
fly()
}
type ISay1 interface{
say()
}
type ISay_Fly interface{
ISay
IFly
}
 
17、接口查询 obj,ok=val.(Interface)   返回查询的接口 并且返回查询结果 
x.(type) 获取类型 只能在switch中用 
x.(OterTypeInterface) 判断x是否是指定接口类型 返回指定接口对象,和查询结果
在Go语言中,还可以更加直截了当地询问接口指向的对象实例的类型,例如:
var v1 interface{} = ...
switch v := v1.(type) {
case int: // 现在v的类型是int
case string: // 现在v的类型是string
...
}
就像现实生活中物种多得数不清一样,语言中的类型也多得数不清,所以类型查询并不经常使用。它更多是个补充,需要配合接口查询使用,例如:
type Stringer interface {
String() string
} func Println(args ...interface{}) {
for _, arg := range args {
switch v := v1.(type) {
case int: // 现在v的类型是int
case string: // 现在v的类型是string
default:
if v, ok := arg.(Stringer); ok { // 现在v的类型是Stringer
val := v.String()
// ...
} else {
// ...
}
}
}
}
当然,Go语言标准库的Println()比这个例子要复杂很多,我们这里只摘取其中的关键部分进行分析。对于内置类型,Println()采用穷举法,将每个类型转换为字符串进行打印。对于更一般的情况,首先确定该类型是否实现了String()方法,如果实现了,则用String()方法将其转换为字符串进行打印。否则,Println()利用反射功能来遍历对象的所有成员变量进行打印。是的,利用反射也可以进行类型查询,详情可参阅reflect.TypeOf()方法的相关文档。此外,
18、 Any类型  对于匿名结构体赋值给任意类型  没法取出 具体每个匿名结构体的内部属性 只能前部打印 通过系统默认的String()函数
var any1 interface{}=
var any2 interface{}="b"
var any3 interface{}=struct{x ,y string}{"hello,world","aaaaa"}
fmt.Println(any1,any2,any3)
由于Go语言中任何对象实例都满足空接口interface{},所以interface{}看起来像是可以指向任何对象的Any类型,如下:
var v1 interface{} =        // 将int类型赋值给interface{}
var v2 interface{} = "abc" // 将string类型赋值给interface{}
var v3 interface{} = &v2 // 将*interface{}类型赋值给interface{}
var v4 interface{} = struct{ X int }{}
var v5 interface{} = &struct{ X int }{}
当函数可以接受任意的对象实例时,我们会将其声明为interface{},最典型的例子是标准库fmt中PrintXXX系列的函数,例如:
func Printf(fmt string, args ...interface{})
func Println(args ...interface{})
...
总体来说,interface{}类似于COM中的IUnknown,我们刚开始对其一无所知,但可以通过接口查询和类型查询逐步了解它。
由于Go语言中任何对象实例都满足空接口interface{},所以interface{}看起来像是可以指向任何对象的Any类型,如下:
var v1 interface{} =        // 将int类型赋值给interface{}
var v2 interface{} = "abc" // 将string类型赋值给interface{}
var v3 interface{} = &v2 // 将*interface{}类型赋值给interface{}
var v4 interface{} = struct{ X int }{}
var v5 interface{} = &struct{ X int }{}
当函数可以接受任意的对象实例时,我们会将其声明为interface{},最典型的例子是标准库fmt中PrintXXX系列的函数,例如:
func Printf(fmt string, args ...interface{})
func Println(args ...interface{})
...
总体来说,interface{}类似于COM中的IUnknown,我们刚开始对其一无所知,但可以通过接口查询和类型查询逐步了解它。

Go语言面组合式向对象编程基础总结的更多相关文章

  1. Python语言基础07-面向对象编程基础

    本文收录在Python从入门到精通系列文章系列 1. 了解面对对象编程 活在当下的程序员应该都听过"面向对象编程"一词,也经常有人问能不能用一句话解释下什么是"面向对象编 ...

  2. C++学习4-面向对象编程基础(面向对象概念,定义类,定义对象)

    什么是面向对象? 在软件的设计过程中的两种方式: 把程序按照算法的执行步骤来拆解,一步步实现,这是面向过程编程: 把程序按照现实世界的理解,分成不同对象,通过多个对象之间的相互作用,来完成程序的最终功 ...

  3. C++学习8-面向对象编程基础(模板)

    模板 模板是一种工具,模板可以使程序员能建立具有通用类型的函数库与类库: 模板具有两种不同的形式: 函数模板 类模板 函数模板 当一个add()函数接收两个参数,因为某种特定情况,所传入的实参数据类型 ...

  4. C++学习7-面向对象编程基础(多态性与虚函数、 IO文件流操作)

    多态 多态性是指对不同类的对象发出相同的消息将返回不同的行为,消息主要是指类的成员函数的调用,不同的行为是指不同的实现: 函数重载 函数重载是多态性的一种简单形式,它是指允许在相同的作用域内,相同的函 ...

  5. C++学习6-面向对象编程基础(运算符重载、类的派生与继承、命名空间)

    运算符重载 重载的运算符是具有特殊名字的函数:它们的名字由关键字operator和其后要定义的运算符号共同组成.重载的运算符是遵循函数重载的选择原则,根据不同类型或不同参数来选择不同的重载运算符. 运 ...

  6. C++学习5-面向对象编程基础(构造函数、转换构造、静态数据成员、静态成员函数、友元)

    知识点学习 类 const作用 C语言的const限定符的含义为"一个不能改变值的变量",C++的const限定符的含义为"一个有类型描述的常量": const ...

  7. Go语言基础之19--web编程基础

    一.web编程基础 1.1 web工作方式 1.2 HTTP协议详解 a.http 请求包体 GET /domains/example/ HTTP/1.1 //请求行: 请求方法 请求URI HTTP ...

  8. 第一章 T-SQL查询和编程基础 T-SQL语言基础(1)

    T-SQL查询和编程基础(1) 1.1 理论背景 SQL是为查询和管理关系型数据库管理系统(RDBMS)中的数据而专门设计的一种标准语言. RDBMS是一种基于关系模型的数据库管理系统,关系模型则是一 ...

  9. Linux基础与Linux下C语言编程基础

    Linux基础 1 Linux命令 如果使用GUI,Linux和Windows没有什么区别.Linux学习应用的一个特点是通过命令行进行使用. 登录Linux后,我们就可以在#或$符后面去输入命令,有 ...

随机推荐

  1. UVa 11270 铺放骨牌(轮廓线DP)

    https://vjudge.net/problem/UVA-11270 题意: 用1×2骨牌覆盖n×m棋牌,有多少种方法? 思路: 这道题目是典型的轮廓线DP题. 所谓轮廓线DP,就是以整行整列为状 ...

  2. POJ 1006 Biorhythnms(中国剩余定理)

    http://poj.org/problem?id=1006 题意: (n+d) % 23 = p ;(n+d) % 28 = e ;(n+d) % 33 = i ; 求最小的n. 思路: 这道题就是 ...

  3. UVa 11806 拉拉队(容斥原理)

    https://vjudge.net/problem/UVA-11806 题意: 在一个m行n列的矩形网格里放k个相同的石子,有多少种方法?每个格子最多放一个石子,所有石子都要用完,并且第一行.最后一 ...

  4. shell 使用ping测试网络

    能ping通返回1,不能返回0 ping -c 192.168.1.1 | grep '0 received' | wc -l

  5. redis的使用及方法

    一.redis (1).redis是一个key-value存储系统.和Memcached类似,它支持存储的value类型相对更多,包括string(字符串).list(链表).set(集合).zset ...

  6. 【测试设计】基于正交法的测试用例设计工具--PICT

    前言 我们都知道成对组合覆盖是一种非常有效的测试用例设计方法,但是实际工作过程中当成对组合量太大,我们往往很难做到有效的用例覆盖. PICT是微软公司出品的一款成对组合命令行生成工具,它很好的解决了上 ...

  7. spark 累加历史 + 统计全部 + 行转列

    spark 累加历史主要用到了窗口函数,而进行全部统计,则需要用到rollup函数 1  应用场景: 1.我们需要统计用户的总使用时长(累加历史) 2.前台展现页面需要对多个维度进行查询,如:产品.地 ...

  8. 前端框架MVVM是什么(整理)

    前端框架MVVM是什么(整理) 一.总结 一句话总结:vm层(视图模型层)通过接口从后台m层(model层)请求数据,vm层继而和v(view层)实现数据的双向绑定. 1.我大前端应该不应该做复杂的数 ...

  9. UVA-1515 Pool construction (最小割)

    题目大意:有一块地,分成nxm块.有的块上长着草,有的块上是荒地.将任何一块长着草的块上的草拔掉都需要花费d个力气,往任何一块荒地上种上草都需要花费f个力气,在草和荒地之间架一个篱笆需要花费b个力气, ...

  10. jQuery中 attr和Prop的区别

    出自这里: http://www.365mini.com/page/jquery_noconflict.htm 在jQuery中,attr()函数和prop()函数都用于设置或获取指定的属性,它们的参 ...