07 Object-oriented programming-structure, encapsulation, inheritance, polymorphism, interface

  1. Golang supports object-oriented programming, but it is different from traditional object-oriented. It is not a purely object-oriented language. It can only be said that Golang supports object-oriented programming features.
  2. Golang has no classes. It implements OOP through the structure struct, which is very concise.

Struct definition

  1. The syntax of the Struct field declaration is the same as that of a variable. After creating a structure, if no value is assigned to the field, the field will be the default value.
  2. The structure can be type redefined, Golang defaults to the new type
  3. The structure is a type defined separately by the user, and needs to have exactly the same fields (name, number, type) when converting with other types
  4. Each field of struct can be written with a tag, which can be obtained through reflection mechanism
  5. All fields of the structure are continuous in memory

Sample code

//声明一个结构体
type Cat struct{
    
    
	Name string
	Age int
	Color string
	Hobby string
}
func test01(){
    
    
	
	//创建结构体并赋值1
	var cat1 Cat
	cat1.Name = "小白"
	cat1.Age = 10
	cat1.Color = "白色"
	cat1.Hobby = "吃 鱼"
	var cat2 Cat
	fmt.Println(cat1,cat2)//{小白 10 白色 吃 鱼} { 0  }
    //创建结构体并赋值2
	c3 := Cat{
    
    "小黑",20,"黑色","shuijiao"}
	 //创建结构体并赋值3
	var c4 *Cat = new(Cat)
	(*c4).Name = "小花" //通过索引访问值 再访问属性
	c4.Age = 10 //也可以直接通过索引访问属性(goLang做了优化)
    //创建结构体并赋值4
	var c5 *Cat  = &Cat{
    
    }
    c5.Name = "c5"
	fmt.Println(cat1,cat2,c3,c4,c5)
	c6 := c3
	c6.Name ="c6"
	//赋值后会直接克隆一个变量给C6,修改c6的值 c3 不受影响
	//{小黑 20 黑色 shuijiao} {c6 20 黑色 shuijiao}
	fmt.Println(c3,c6)
	//创建结构体变量时直接指定字段值
	var c7 = Cat{
    
    
				Name:"小绿",
				Age:40,
				}
	fmt.Println(c7)	

}
type Point struct{
    
    
	x int
	y int
}
type Rect struct{
    
    
	leftUp, rightDown Point
}
type Rect2 struct{
    
    
	leftUp, rightDown *Point
}


func test02(){
    
    

	//结构体所有字段在内存中是连续的
	r1 := Rect{
    
    Point{
    
    1,2} , Point{
    
    3,4}}
	fmt.Printf("r1.rd.x地址= %p r1.rd.y地址= %p r1.lu.x地址= %p r1.lu.y地址= %p  \n",
	&r1.rightDown.x,&r1.rightDown.y,&r1.leftUp.x,&r1.leftUp.y)
	//	fmt.Printf("r1.rd.x地址= %p r1.rd.y地址= %p r1.lu.x地址= %p r1.lu.y地址= %p  \n",
	//&r1.rightDown.x,&r1.rightDown.y,&r1.leftUp.x,&r1.leftUp.y)
	r2 := Rect2{
    
    &Point{
    
    1,2} , &Point{
    
    3,4}}
	fmt.Printf("r2.rd.x地址= %p r2.rd.y地址= %p r2.lu.x地址= %p r2.lu.y地址= %p  \n",
	&r2.rightDown.x,&r2.rightDown.y,&r2.leftUp.x,&r2.leftUp.y)

	//结构体是用户单独定义的类型,和其他类型转换时需要有完全相同的字段(名字、个数、类型)
	
	type A struct{
    
    
		Num int
	}
	type B struct{
    
    
		Num int
	}
	var a A
	var b B
	a = A(b)
	a.Num =10
	fmt.Println(a,b)
	
	//结构体进行type 重新定义,Golang默认是新类型,
	type AA A
	var aa AA
	//var a A = aa 报错需要强转
	var a3 A = A(aa)
	fmt.Println(aa,a3)
	//struct 每个字段 都可以写上一个tag,该tag 可以通过反射机制获取
	//常见的场景就是 序列化和反序列化
	type Monster struct {
    
    
		Name string `json:"name"`
		Age int `json:age`
	}
	m1 := Monster{
    
    "牛魔王",300}
	jsonstr ,err := json.marshal(m1)
	if err != nil {
    
    
		fmt.Println("json 字符串处理错误")
	}
	fmt.Println("json 字符串=",jsonstr)
}

struct method

The struct method declaration syntax indicates that the A structure has a test method (a A) to indicate that this method is bound to the A type

func( a A)test(){
    
    } 
func( a A)test2(参数列表)(返回值列表){
    
    
		方法体
	return 返回值
} 

important point

  1. When calling a method through a structure variable, the calling mechanism is the same as the function, except that when the structure method is called, the structure variable is also passed to the method as a parameter.
  2. The method in Golang is specified on the data type, so all custom types can have methods, including struct, int, float32
  3. If a type implements the String() method, then fmt.Println will call this method of the variable as the result output by default
  4. When calling a method through a variable, its (parameter transfer) mechanism is the same as that of a function. The difference is that the variable itself is also passed to the method as a parameter (if the variable is a value type, value copy is performed, if it is a reference type, geological Copy, if you want to modify the value of the structure in the method, you can use a pointer to pass).
  5. The method's access scope control is the same as that of the function. The first letter of the method name can only be accessed in the package in lowercase, and the uppercase can be accessed outside the package.

Sample code

//定义结构体
type Person struct{
    
    
	Name string
}
//定义方法
func (p Person) speak(){
    
    
	fmt.Println(p.Name,"是一个好人")
}
func test03(){
    
    
	p := Person{
    
    "zhangsan"}
	p.speak()
}

Factory mode

The factory pattern is used to create (only available in the package/lowercase structure) instance by a specified method.
And if the first attribute structure lowercase class can also be obtained by a process (similar to the set / get the method java)
example code

func test04(){
    
    
	var stu = mode.NewStudent("tom",12.0)
	fmt.Println(*stu)
	fmt.Println(stu.Name,stu.GetScore())
}
package model

type student struct{
    
    
	Name string
	score float64
}
//通过工厂方法获取 隐藏结构的实例
func NewStudent(n string,s float64) *student{
    
    
	return &student{
    
    Name:n,score:s}
}
//通过方法或去被封装的属性
func( stu *student) GetScore () float64{
    
    
	return stu.score
}

Three object-oriented features

Golang also has three major features of object-oriented programming, but the implementation is different from other OOP languages

Encapsulation

Encapsulate the abstracted fields together.
Benefits: hide the implementation details and use the unified access method to verify the data and ensure the rationality of the data
.

  1. Lowercase the first letter of the structure and field (similar to java private)
  2. Provide factory mode functions for the encapsulated structure, with the first letter capitalized, similar to a constructor
  3. Provide the Set/Get method with the first letter capitalized for the structure to be used for property reading and writing
    sample code
func test05(){
    
    
	var per = mode.NewPerson("TOM")
	per.SetAge(50)
	per.SetSal(10000.0)
	fmt.Println(per)
	fmt.Println(per.GetAge(),per.GetSal(),per.Name)

}
package model
import (
	"fmt"
)
type person struct{
    
    
	Name string
	age int
	sal float64
}
// 封装工厂方法 创建结构体实例
func NewPerson(name string) *person{
    
    
	return &person{
    
    
		Name:name,
	}
}
func (p *person)SetAge(age int){
    
    
	if age>0 && age<150{
    
    
		p.age = age 
	} else{
    
    
		fmt.Println("年龄不在合法范围内")
	}

}

func (p *person)SetSal(sal float64){
    
    
	if sal>3000 && sal<30000{
    
    
		p.sal = sal 
	} else{
    
    
		fmt.Println("薪资不在合法范围内")
	}
}
func (p *person)GetAge() int {
    
    
	fmt.Println("====>",p.age)
	return p.age
}

func (p *person)GetSal() float64 {
    
    
	fmt.Println("====>",p.sal)
	return p.sal
}

inherit

Inheritance can solve code reuse. When multiple structures have the same fields and methods, a structure can be abstracted to contain public properties and methods. Other structures do not need to define these properties and methods, only need to nest this structure.
That is to say, if a structure is nested with another anonymous structure, then this structure can directly access the methods and fields of the anonymous structure, thus achieving inheritance.
Basic grammatical form

type Goods struct{
    
    
	Name string
	Price int
}
type Book struct{
    
    
	Goods //嵌套匿名结构体
	Writer string
}

Sample code

func test06(){
    
    
	pu := &Pupil{
    
    }
	pu.Student.Name = "TOM"
	pu.Student.Age =12
	pu.Age=13//对继承的字段可以简化访问
	pu.testing();
	pu.Student.ShowInfo()
	pu.ShowInfo()//方法简化访问
	//声明结构体时直接为嵌套结构体赋值
	pu2 := &Pupil{
    
    
		Student{
    
    Name: "Jack",
			Age:19,
			Score:100,
		},
	}
	pu2.ShowInfo()
}
//定义学生类
type Student struct{
    
    
	Name string
	Age int
	Score int
}
//显示学生信息
func (stu *Student)ShowInfo(){
    
    
	fmt.Println(stu)
}
func (stu *Student) SetCore(score int){
    
    
	stu.Score = score
}
//定义小学生类
type Pupil struct{
    
    
	Student//嵌入 学生结构体
}
func (p *Pupil) testing(){
    
    
	fmt.Println("小学生正在考试...")
}

important point

  1. The structure can use all the fields and methods of the anonymous structure, regardless of whether the first letter is uppercase or lowercase
  2. Structure access Anonymous structure methods and properties can be simplified, simplifying the access logic during access: if the current structure has access properties/methods, directly call the properties/methods of this structure, if the current structure does not have the properties/methods, then Look for the attribute/method in the nested anonymous structure, call it when it is found, and report an error if it is not found.
  3. When the structure and the nested structure have the same properties or methods, the compiler adopts the principle of nearest access. If you want to call the properties/methods in the anonymous structure, you must call them by the name of the anonymous structure (simplified calls cannot be made)
  4. If a structure has multiple structures nested, and multiple nested structures contain the same properties/methods, then the anonymous structure name must be specified when calling. Otherwise, the compiler reports an error
  5. If a structure is nested with a named structure, then the two are a combination relationship. At this time, you must bring the name of the structure when accessing the properties/methods of the composite structure.
  6. After nesting structure variables, you can directly assign values ​​to the nested structure when creating structure variables.
  7. If a basic data type such as int is nested in a structure, the access method is A.int=12, if there are multiple int fields, the name must be specified

Multiple inheritance
If a struct is nested with multiple anonymous structures, then it can access all the fields and methods of the structure. This is Golang's multiple inheritance
* If multiple nested structures contain the same attributes/methods, then The name of the nested structure must be specified when calling the method

interface

The interface type can define a set of methods, but does not need to be implemented, and the interface cannot contain any variables. These methods are implemented in the concrete type according to the actual situation.

type 接口名 interface{
    
    
	method1()
	method2()
}

Sample program

type Gun interface{
    
    
	Fire()
}
type Gun51 struct{
    
    
	
}
func(g Gun51) Fire(){
    
    
	fmt.Println("Gun51连续发射7mm子弹...")
}
type GunRPG struct{
    
    
	
}
func(g GunRPG) Fire(){
    
    
	fmt.Println("RPC发射火箭弹...")
}
func test07(){
    
    
	var g51 Gun51
	var rpg GunRPG
	var gun Gun = g51
	gun.Fire();
	gun = rpg
	gun.Fire()
}

important point

  1. All methods in the interface have no method body, which reflects the idea of ​​high cohesion and low coupling of the program
  2. Golang does not explicitly implement the interface. As long as a variable contains all the methods declared by the interface , it is considered that the variable implements the interface.
  3. The interface itself does not create an instance, but can point to an instance that implements the interface
  4. A custom type can only assign a variable of the type to this interface only if it implements a certain interface.
  5. Any custom type can realize the interface is not necessarily a structure, and a variable can realize multiple interfaces
  6. Interface A can inherit multiple other interfaces B and C. At this time, if the variable implements the A interface, it must also implement the B and C interfaces at the same time. If the interface (including the inherited interface) contains duplicate methods, the compiler reports an error
  7. interface is a pointer type by default, if it is not initialized, the default output is nil
  8. The empty interface has no methods, all types implement the empty interface, that is, all types can be assigned to the empty interface

Inheritance and interface comparison
Inheritance mainly solves the reusability and maintainability of code. Emphasize common reuse.
The interface is mainly a design specification, let other types comply with the specification. Emphasize the realization of common capabilities.
The interface achieves code decoupling to a certain extent

Polymorphism

Variables have many forms, and polymorphism in Golang is implemented through interfaces. According to different implementations of the same interface in different variables, the interface presents a variety of different states. (See the interface example)
Polymorphism is generally reflected by method parameters

Type assertion
How to assign an interface variable to a custom type variable? Need to determine the type of the variable first, that is, type assertion
sample code

func test08(){
    
    
	var x interface{
    
    }
	var b2 int = 1
	x = b2
	// 将x 转换为int  
	y, ok := x.(int); 
	if ok {
    
    
		fmt.Printf("转换成功 y的类型是%T 值是=%v \n",y,y);
	}else{
    
    
		fmt.Println("转换失败")
	}
	fmt.Println("x.(int)==>",x.(int))
	//fmt.Println("x.(type)==>",x.(type)) 只能在switch 中使用 这里使用报错
	//调用断言方法
	TypeJudge(b2)
}

func TypeJudge(items... interface{
    
    }){
    
    
	for index,x := range items{
    
    
		switch x.(type){
    
    
		case bool :
			fmt.Printf("第%v个参数是 bool 类型,值是 %v \n",index,x)
		case float32:
			fmt.Printf("第%v个参数是 float32 类型,值是 %v \n",index,x)
		case float64:
			fmt.Printf("第%v个参数是 float64 类型,值是 %v \n",index,x)
		case int,int32,int64:
			fmt.Printf("第%v个参数是 int 类型,值是 %v \n",index,x)
		case string:
			fmt.Printf("第%v个参数是 string 类型,值是 %v \n",index,x)
		default:
			fmt.Printf("第%v个参数 类型不确定,值是 %v \n",index,x)

		}
	}
}

Guess you like

Origin blog.csdn.net/zhangxm_qz/article/details/114681802