mtchuyen / Golang-Tips

Tips in Golang programming
3 stars 2 forks source link

OO (object oriented) in Go #34

Open mtchuyen opened 2 years ago

mtchuyen commented 2 years ago

OO in Go

https://grigsby.dev/oo-in-go-go-d49d8e73255a

Inheritance-in-Go

https://alenalex.medium.com/inheritance-in-go-82212be68576

Object-oriented Programming in Go

https://medium.com/@mmisyaath/object-oriented-programming-in-go-199de8efae15

Keywords:

mtchuyen commented 1 year ago

Lập trình hướng đối tượng với Go

https://viblo.asia/p/lap-trinh-huong-doi-tuong-voi-go-07LKXA7kZV4

https://techmaster.vn/posts/34913/go-co-phai-la-1-ngon-ngu-lap-trinh-huong-doi-tuong

Composition trong Go

https://kungfutech.edu.vn/bai-viet/go/composition-trong-go

https://golangbot.com/inheritance/

https://www.tutorialspoint.com/composition-in-golang

Composition:

Go is not an OOP language, it doesn't have inheritance, but can use Composition instead.

3. Tác dụng của Composition

Sử dụng Composition có thể giúp chúng ta:

Giả sử ta định nghĩa 1 type có tên là Context, và nó có 1 method là Get

type Context struct {
    kv map[string]string
}

func (c *Context) Get(k string) string {
    return c.kv[k]
}

Giờ ta sẽ định nghĩa 1 type mới có tên là BusinessContext

type BusinessContext struct {
    Context
}

Ta gọi Contextembed typed của BusinessContext

3.1. Reusability & Reduce

Giờ ta sẽ làm cụ thể 2 vấn đề Reusability & Reduce, vẫn với 2 type đã định nghĩa ở trên

ctx := &Context{kv:map[string]string{"name":"Pallat"}}
bctx := &BusinessContext{ctx}

println(bctx.Get("name"))

như vậy type BusinessContext đã re-used lại method .Get của type Context, và không cần phải viết lại code (reduce)

3.2. Extensibility

Ở ví dụ trên, có nhược điểm là nếu cấp API ra ngoài, thì người dùng không thể biết được trong type Contextkey/value = name/<<ex:Pallat>>.

Vậy nên type BusinessContext viết thêm 1 method giúp người dùng thuận tiện hơn

func (c *BusinessContext) Name() string {
    return c.Context.Get("name")
}

như vậy 2 dòng code dưới đây là tương đương nhau

println(bctx.Get("name"))
println(bctx.Name())

nhờ tính năng Composition của Go, nên việc mở rộng method trong việc "kế thừa" (thực tế là re-used) dễ dàng hơn.

3.3. Cẩn trọng với Override

Ở ví dụ trên, bctx.Get("name") sẽ gọi tới method .Get của type Context. Lúc này có thể hiểu type BusinessContext cũng có 1 method .Get (nhưng thực ra là của Context)

Function .Get (của lời gọi bctx.Get("name")) có thể được mở rộng hơn (Extensibility) bằng cách định nghĩa một method mới cho type BusinessContext:

func (c *BusinessContext) Get(k string) string {
    return c.Context.Get(k) + "was calling (được gọi tới)"
}

Và vẫn dùng bình thường: bctx.Get("name"). Đó là sự Override

Go Composition vs Inheritance

http://jim-mcbeath.blogspot.com/2019/11/go-composition-vs-inheritance.html

https://www.digitalocean.com/community/tutorials/composition-vs-inheritance

Tìm hiểu về nguyên lý "Composition over Inheritance"

https://viblo.asia/p/tim-hieu-ve-nguyen-ly-composition-over-inheritance-YWOZr0or5Q0 https://daynhauhoc.com/t/tim-hieu-ve-nguyen-ly-composition-over-inheritance/42665

https://en.wikipedia.org/wiki/Composition_over_inheritance

https://odetocode.com/blogs/scott/archive/2019/01/03/composition-over-inheritance-in-go.aspx

https://stackoverflow.com/questions/49002/prefer-composition-over-inheritance

Composition và Inheritance là 2 kĩ thuật trong các kĩ thuật để tránh vấn đề Duplication bằng cách reuse từ class khác, thay đổi 1 số thành phần. Inheritance thực thi tại compile time, có thể nhìn thấy cơ chế reuse của nó. Ngược lại, composition thực thi ở runtime, khó nhìn thấy cách reuse. Đối với app nhỏ thì composition hay inheritance không có sự khác biệt, đọc code là hiểu ngay, nhưng khi app phát triển, thì lập trình viên khó hiểu cách reuse ở composition hơn là ở inheritance. Quy trình phát triển phần mềm hiện tại là quy trình Agile, app phải đáp ứng được yêu cầu thay đổi (change) nên người ta chuộng composition hơn nheritance. Vì họ có thể thay đổi cơ chế kế thừa tại runtime mà không cần tác động source code, chỉ cần tạo file mới. Trong khi đối với inheritance, phải compile lại nguyên toàn bộ class hierarchy, và khi change requirement xảy ra ở superclass thì tất cả subclasses đều bị ảnh hưởng.

cái này hôm trước có đọc 1 cái ví dụ trong cuốn HeadFirstDesignPatterns nó giải thích rất rõ ràng về vấn đề này tùy vào từng trường hợp mà áp dụng cho hợp lý làm sao đảm bảo được sự linh hoạt của chương trình , chứ không phải cứ dùng composition là tốt đâu mấy cái này liên quan đế thiết kế hướng đối tượng …trên youtube cũng có vài video nói về cái này mà mình thấy ông nào cũng đưa vd đúng của mình ra để cãi cả nên…:grin:

Hầu hết ngôn ngữ lập trình ra đời gần đây toàn loại bỏ tính năng inheritance. Golang là 1 ví dụ, Go chỉ sử dụng composition thôi. Mới đây thì Apple giới thiệu ngôn ngữ Swift, trong Swift đưa ra khái niệm mới là Value Type, cũng không có inheritance.

mtchuyen commented 10 months ago

Second Life of OOP

an object is some data (a block of memory) with attached logic (behavior) that can access that data.


// this is a type alias that gives a name to a specific data structure
type StringTable struct {
    values [][]string
}

// outside of the type declaration, attached to an existing type
func (s StringTable) NoOp() { }

// define a readable CSV representation for the StringTable
func (s StringTable) String() string {
    lines := make([]string, 0)
    for _, row := range s.values {
        lines = append(lines, strings.Join(row, ","))
    }
    return strings.Join(lines, "\n")
}

Pillars of OOP: Encapsulation

Encapsulation: This pillar is all about controlling access to the enclosed (encapsulated) data in an object.

Traditionally, languages use private and public (and sometimes protected) field modifiers to set access and visibility.

In Go access and visibility works on a package level and follows a convention of UPPERCASE names for public (visible outside of the current package) and lowercase for private (visible within the package).

Pillars of OOP: Inheritance and Polymorphism

This is where it gets tricker with Go.

Pillars of OOP: Polymorphism

Polymorphism in Go feels a little different as well.

Instead of polymorphism through inheritance, Go have **interfaces: Various types can implement an interface