OOP思想
Go语言不是面向对象语言,只是让大家理解一些面向对象的思想,通过一些方法来模拟面向对象
语言的进化发展跟生物的进化发展是一回事,都是"物以类聚"
语句多了,我们将完成同样功能相近的语句,聚到一块,便于我们使用,于是,函数出现了
变量多了,我们将功能相近的变量组在一起,聚到一起归类,便于我们调用。于是,结构体出现了
再后来,方法多了,变量多了!结构体不够用!我们就将功能相近的变量和方法聚到了一起,于是类和对象就出现了
企业的发展也是"物以类聚"的过程,完成市场维护的人员聚到了一起形成了市场部。完成技术开发的人员聚到了一起形成了开发部
面向对象的思维模式
面向对象的思维模式是简单的线性思维,思考问题首先陷入第一步做什么,第二步做什么的细节中,这种思维模式适合处理简单的事情,比如:上厕所
如果面对复杂的事情,这种思维模式会陷入令人发疯的状态!比如:如何造火箭!
面向对象的思维模式
面向对象的思维模式说白了就是分类思维模式,首先思考解决问题,需要哪些分类,然后对这些分类进行单独思考。最后,才对某个分类下的细节进行面向过程的思索
这样就可以形成很好的协作分工。比如:架构师分了10个类,然后将10个类交给了10个人分别进行详细设计和编码!
显然,面向对象适合处理复杂的问题,适合处理需要多人协作的问题!
如果一个问题需要多人协作一起解决,那么你一定要用面向对象的方式来思考!
对于描述复杂的事物,为了从宏观上把握、从整体上合理分析,我们需要使用面向对象的思路来分析整个系统。但,仍然需要面向过程的思路去处理。
面向对象的三大特点:封装、继承、多态I
继承
兔子和羊属于食草动物类,狮子和豹属于食肉动物类。
食草动物和食肉动物又是属于动物类。
所以继承需要符合的关系是: is-a,父类更通用,子类更具体。
虽然食草动物和食肉动物都是属于动物,但是两者的属性和行为上有差别,所以子类会具有父类的一般特性也会具有自身的特性。
继承就是子类继承父类的特征和行为,使得子类具有父类的属性和方法,使得子类具有父类相同的行为。子类会具有父类的一般特性也会具有自身的特性。
package main
import "fmt"
/*
Go语言的结构体嵌套
1、模拟继承性:is - a
type A struct{
field
}
type B struct{
A//匿名字段
//b就可以直接访问a的属性了
}
2、模拟聚合关系:has -a
type C struct{
field
}
type D struct{
c C //聚合关系
}
//D就不能直接访问c当中的属性,需要通过D.C.xx访问
}
*/
// 定义一个父类结构体
type Person struct {
name string
age int
}
// 定义一个子类结构体
type Student struct {
Person //匿名结构体
school string
}
func main() {
//创建一个父类的对象
p1 := Person{"张三", 18}
fmt.Println(p1)
//创建一个子类的对象
s1 := Student{Person{"秦疆", 18}, "清华"}
fmt.Println(s1.Person.name)
fmt.Println(s1.name)
// 提升字段
// 对于student来说,person是匿名字段,person中的属性name,age就叫做提升字段
// 提升字段可以通过名字直接访问,不需要再通过结构体名person
var s3 Student
s3.name = "kuangshen"
s3.school = "北大"
fmt.Println(s3)
}
/*
{张三 18}
秦疆
秦疆
{{kuangshen 0} 北大}
*/
方法讲解
什么是方法
Go语言中同时拥有函数和方法
- 方法:
- 某个类别的行为功能。需要指定接收者调用
- 一段独立的功能代码,可以直接调用
- 函数
- 一段独立功能的代码,可以直接调用
- 命名不能冲突
package main
import "fmt"
// 定义一个Dog的结构体
type Dog struct {
name string
age int
}
// 定义一个Cat的结构体
type Cat struct {
name string
age int
}
// 定义方法,接受者为Dog类型
func (dog Dog) eat() {
fmt.Println("dog...eating")
}
func (dog Dog) sleep() {
fmt.Println("dog..sleep")
}
func (cat Cat) eat() {
fmt.Println("cat...eating")
}
func main() {
//接收者对象dog,设置结构体的属性
dog := Dog{"二哈", 3}
//调用方法
dog.eat()
dog.sleep()
cat := Cat{"TD", 5}
cat.eat()
}
/*
dog...eating
dog..sleep
cat...eating
*/
方法重写
子类可以重写父类的方法override
子类可以新增自己的属性和方法
子类可以直接访问父类的属性和方法
package main
import (
"fmt"
)
type Animal struct {
name string
age int
}
// 同一包下结构体重名 +s
type Dogs struct {
Animal
sex string
}
type Cats struct {
Animal
color string
}
func (animal Animal) eat() {
fmt.Println("吃吃吃~~~")
}
func (animal Animal) sleep() {
fmt.Println("睡觉觉~~~")
}
// 方法的重写
func (dogs Dogs) eat() {
fmt.Println("dog正在吃吃吃~~~")
}
func (cats Cats) sleep() {
fmt.Println(cats.name, "正在睡觉觉~~~")
}
func main() {
dog := Dogs{Animal{"旺财", 3}, "公"}
dog.Animal.eat() //调用父类方法
dog.eat() //调用父类重写之后的方法
cat := Cats{Animal{"TD", 2}, "red"}
cat.sleep()
}
/*
吃吃吃~~~
dog正在吃吃吃~~~
TD 正在睡觉觉~~~
*/
接口实现
Go语言提供了另外一种数据类型即接口,它把所有的具有共性的方法定义在一起,任何其他类型只要实现接口定义的全部方法就是实现了这个接口
接口只做定义,不做具体的方法实现,具体实现交给实现方法
// go语言不需要显示的接口
// 实现接口中的方法,就算实现了接口
// go语言中,接口和实现类的关系,是非侵入式的
package main
import "fmt"
// 定义一个USB的接口,以及接口中有两个方法
type USB interface {
oInput()
oOutput()
}
// 定义一个Mouse鼠标结构体
type Mouse struct {
name string
}
// 接口方法实现,当接口中的所有方法都被调用时旁边才会出现I图标
func (mouse Mouse) oInput() {
fmt.Println(mouse.name, "鼠标输入")
}
func (mouse Mouse) oOutput() {
fmt.Println(mouse.name, "鼠标输出")
}
// 示列二:定义一个Keyboard键盘结构体
type Keyboard struct {
name string
}
func (k Keyboard) oInput() {
fmt.Println(k.name, "键盘输入")
}
func (k Keyboard) oOutput() {
fmt.Println(k.name, "键盘输出")
}
// 测试方法 传递一个USB的对象,这里也可以传入一个Mouse的对象
func test(u USB) {
//将传入的对象调用方法
u.oInput()
u.oOutput()
}
func main() {
//通过传入接口实现类,来进行具体方法的调用
m := Mouse{"罗技"}
//调用测试方法
test(m)
k := Keyboard{"雷蛇"}
test(k)
var u USB
u = k
fmt.Println(u)
//fmt.Println(u.name) 这里会报错,只能给予赋值,不能赋予属性
}
/*
罗技 鼠标输入
罗技 鼠标输出
雷蛇 键盘输入
雷蛇 键盘输出
{雷蛇}
*/
多态
多态:一个事务拥有多种形态,是面向对象中很重要的一个特点
Go语言通过接口来模拟多态
package main
import "fmt"
// 定义一个Animal2接口
type Animal2 interface {
eat()
sleep()
}
// 定义结构体
type Dog2 struct {
name string
}
// 方法实现
func (dog2 Dog2) eat() {
fmt.Println(dog2.name, "eat..")
}
func (dog2 Dog2) sleep() {
fmt.Println(dog2.name, "sleep..")
}
// 测试方法 接收Animal2的参数对象
func test2(animal2 Animal2) {
fmt.Println("test2")
}
func main() {
//Dog2
dog2 := Dog2{"哈士奇"}
dog2.eat()
dog2.sleep()
//Animal2
test2(dog2)
}
/*
哈士奇 eat..
哈士奇 sleep..
test2
*/
空接口
不包含任何的地方,正因为如此,所有的类型都实现了空接口,因此空接口可以存储任意类型的值
package main
import "fmt"
type Dog3 struct {
name string
}
type Cat3 struct {
name string
color string
}
func test3(a A) {
//接收参数打印输出,这里如果是test3,则为test3的地址
fmt.Println(a)
}
func test4(in interface{}) {
fmt.Println(in)
}
// 空接口
type A interface {
}
func main() {
a1 := Dog3{"大黄"}
a2 := Cat3{"喵喵", "白色"}
var a3 A = "嘿嘿嘿"
var a4 A = 100
a5 := A("heh")
fmt.Println(a1)
fmt.Println(a2)
fmt.Println(a3)
fmt.Println(a4)
fmt.Println(a5)
test3(a1)
test3(a2)
test3(a3)
// map 通过make函数创建 类型为map 输入类型为string 传入参数为interface{}任意类型
map1 := make(map[string]interface{})
map1["name"] = "旺财" //传参为string类型
map1["age"] = 18 //传参为int
map1["dog"] = Dog3{"二哈"} //传参为对象
fmt.Println(map1)
// 切片
s1 := make([]interface{}, 0, 10) //切片类型,存储对象为interface{}任意类型,长度为0,容量为10
s1 = append(s1, a1, a2, a3, a4, a5, "hhhhhhh", 1000) //可以将其他参数添加进去,也可以自行创建添加
fmt.Println(s1)
}
/*
{大黄}
{喵喵 白色}
嘿嘿嘿
100
heh
{大黄}
{喵喵 白色}
嘿嘿嘿
map[age:18 dog:{二哈} name:旺财]
[{大黄} {喵喵 白色} 嘿嘿嘿 100 heh hhhhhhh 1000]
*/
接口嵌套
接口可以继承,还可以多继承
package main
import "fmt"
type A2 interface {
testa()
}
type B2 interface {
testb()
}
// C2继承A2和B2接口
type C2 interface {
A2
B2
testc()
}
type Dogg struct {
}
// 要实现testc的方法吧,必须先实现testb和testa
func (dogg Dogg) testc() {
fmt.Println("testc")
}
func (dogg Dogg) testb() {
fmt.Println("testb")
}
func (dogg Dogg) testa() {
fmt.Println("testa")
}
func main() {
var dog Dogg = Dogg{}
//A2和B2的接口,创建的对象ia和ib只能调用自己的方法 不能调用ic方法
var ia A2 = dog
ia.testa()
var ib B2 = dog
ib.testb()
//而ic由于继承了ia和ib的方法,所以ic都可以调用它们的方法
var ic C2 = dog
ic.testc()
ic.testb()
ic.testa()
}
/*
testa
testb
testc
testb
testa
*/
接口断言
检查接口类型变量的值是否实现了期望的接口,就是检查当前接口类型的值有没有实现指定的接口
把接口类型变量的值转换为其他类型或其他接口,go语言空interface{}可以保存任何类型的变量,当程序中需要使用变量的时候,需要把接口类型变量的值转换为具体类型,可以通过接口类型断言
其实很好理解,假如接口类型保存的值时数字,当前的值要参与数学运算,就必须转为int类型才可以参加运算,这就是利用接口断言来实现类型转换的例子
被断言的对象必须是接口类型,否则会报错
t:=i.(T)
t:=i.(T)
/*
断言成功,则t为T类型的接口值
断言失败则报错:panic
*/
v,ok :=i.(T)
v,ok :=i(T)
/*
断言成功,则v为T类型的接口值,ok为true
断言失败,则v为空值,ok为false
*/
type-switch
type switch
switch 接口变量.(type){
case 类型1:
//变量是类型1是的处理
case 类型2:
//变量是类型2是的处理
case nil:
//空接口进入此流程
default:
//变量不是所有case中列举的类型时的处理
}
package main
import "fmt"
//定义一个空接口i
type I interface {
}
func test08(i interface{}) {
switch i.(type) { //默认为空
case string: //判断是否为string类型 以此类推
fmt.Println("string")
case int:
fmt.Println("int")
case bool:
fmt.Println("bool")
case I:
fmt.Println("I")
case nil:
fmt.Println("nil")
}
}
func assertstring(i interface{}) {
s := i.(string) //判断接口变量i是否为string类型
fmt.Println(s)
}
func assertint(i interface{}) {
s, ok := i.(int)
if ok {
fmt.Println("yes,接口变量是int类型", s)
} else {
fmt.Println("no,接口变量非int类型", s)
}
}
func main() {
a := "sss"
b := 10
c := true
var i I
test08(a)
test08(b)
test08(c)
test08(i)
assertstring("abc")
//assertstring(12) 错误信息:panic: interface conversion: interface {} is int, not string
assertint(12)
assertint("qwe")
}
/*
string
int
bool
nil
abc
yes,接口变量是int类型 12
no,接口变量非int类型 0
*/
type别名
自定义类型
package main
import "fmt"
type Diyint int
类型别名
package main
import "fmt"
func main(){
type myint =int
var d myint = 30
}
package main
import "fmt"
// 通过type关键字的定义,Diyint是一种新的类型,它具有int的特性
// 它在函数外部定义,会影响到我们int类型的使用
type Diyint int
func main() {
var a Diyint = 10
var b int = 20
//这里会报错fmt.Println(a+b),若想要计算使用,需要进行转换
c := int(a) + b
fmt.Println(c)
// 在函数内部定义
//myint 只会在代码中存在,编译完成时并不会有myint类型
type myint = int
var d myint = 30
var e int = 40
f := d + e
fmt.Println(f)
}
/*
30
70
*/
标签:func,int,fmt,接口,Println,面向对象编程,Go,狂神,type
From: https://www.cnblogs.com/DuPengBG/p/17011217.html