序
最近在学习go,go里没有class,像C一样是面向过程的。但是实际上也能实现封装,继承,多态这三个面向对象核心思想。回想起平时工作中的代码,虽然是用java写的,但大部分写的其实都是和面向过程的代码。回想起以前看过的一篇公众号文章,略有感悟。
封装,继承,多态
kotlin例子
open class Person(
open val name: String,
open val age: Int
) {
open fun work(): String {
return "do something..."
}
}
class Teacher(
override val name: String,
override val age: Int,
val school: String
) : Person(name, age) {
override fun work(): String {
return "teaching at $school"
}
}
class Student(
override val name: String,
override val age: Int,
val school: String
) : Person(name, age) {
override fun work(): String {
return "learning at $school"
}
}
fun main() {
val li: Person = Teacher("li", 30, "yu cheng high school")
val wong: Person = Student("wong", 18, "yu cheng high school")
work(li) // li work: teaching at yu cheng high school
work(wong) // wong work: learning at yu cheng high school
}
fun work(person: Person) {
println("${person.name} work: ${person.work()}")
}
封装:Person类封装了name,age属性和work方法
继承:Teacher和Student类继承了Person,并扩展了school属性。重载了work方法
多态:${person.work()}根据不同的类,有不同的行为
一个很简单的例子,还是体现了封装,继承,多态思想。kotlin作为面向对象语言实现起来还是很轻松容易的。
go例子
type Person struct {
name string
age int
}
type Worker interface {
work() string
}
func (p Person) work() string {
return "do something..."
}
type Teacher struct {
Person
school string
}
func (t Teacher) work() string {
return fmt.Sprintf("teaching at %v", t.school)
}
type Student struct {
Person
school string
}
func (t Student) work() string {
return fmt.Sprintf("learning at %v", t.school)
}
func main() {
li := Teacher{Person: Person{name: "li", age: 30}, school: "yu cheng high school"}
wong := Student{Person: Person{name: "wong", age: 18}, school: "yu cheng high school"}
work(li) // worker: teaching at yu cheng high school
work(wong) // worker: learning at yu cheng high school
}
func work(worker Worker) {
fmt.Printf("worker: %v\n", worker.work())
}
封装:Person struct封装了name,age属性。(p Person) work()封装了work方法
继承:go没有继承,但是可以通过组合来实现。
多态:通过Worker interface接口作为多态扩展
go作为一门面向过程语言,虽然实现面向对象不如其他面向对象语言那么容易,毕竟没有直接的相关概念,但也的的确确能实现,而且个人认为也直指本质。
- 封装说白了其实就是数据结构+行为函数,其他面向对象语言用一个关键字整合了一下罢了。
- 继承事实上劣于组合,平时工作中也提倡组合优先于继承。
- 多态本质上其实是函数指针,运行时执行指针指向的具体函数罢了。
指针
以前大一刚开始学习编程的时候,入门就是C语言,相信很多同学都是从C开始的。指针是C语言的精华,但是以前一直不理解,只知道指针本质就是内存地址,但是作用啥的,一直理解不了。而且java里也没指针,所以后来一直没有思考过这个问题。
在学习go的过程中,官网教程里有一段代码
type Vertex struct {
X, Y float64
}
func (v Vertex) Abs() float64 {
return math.Sqrt(v.X*v.X + v.Y*v.Y)
}
func (v *Vertex) Scale(f float64) {
v.X = v.X * f
v.Y = v.Y * f
}
func main() {
v := Vertex{3, 4}
v.Scale(10)
fmt.Println(v.Abs())
}
type Vertex struct {
X, Y float64
}
func Abs(v Vertex) float64 {
return math.Sqrt(v.X*v.X + v.Y*v.Y)
}
func Scale(v *Vertex, f float64) {
v.X = v.X * f
v.Y = v.Y * f
}
func main() {
v := Vertex{3, 4}
Scale(&v, 10)
fmt.Println(Abs(v))
}
v.Scale(10)
看起来很像面向对象的风格对吧,instance.method()。但是呢,实际上这个和Scale(&v, 10)
本质上是一样的。如果把指针v
换一下,换成SELF
,那么看起来是不是和python一样了。如果语言支持隐式的SELF
,那么写起来是不是就和java一样。所以,java class里的方法,其实都隐含了一个指向自己的SELF
指针,或者叫做this
,所以java其实也是有指针的。
总结
以前有个leader说过一句"名言":重要的是思想。一门语言是面向过程还是面向对象其实并不重要。面向过程语言也能写得和面向对象一样,而面向对象语言 ,如果不理解面向对象思想的话,写出来的代码还是和面向过程一样的。