Original link: How to use Go language to write object-oriented style code
Preface
Hello, everyone, my name isasong
. In the previous article: , a detailed explanation of the context package that Xiaobai can understand: from entry to proficiency analyzingcontext
, we saw a programming method that embeds an anonymous interface in the structure. MostGo
language seem awkward. In fact, the embedded anonymous interface and anonymous structure in the structure are an implementation method of inheritance and rewriting in object-oriented programming. I have writtenjava
andpython
You should be familiar with inheritance and rewriting in object-oriented programming, butGo
language is procedural-oriented code, so this article will analyze how to write object-oriented codeGo
Object-oriented programming is a computer programming architecture, the English full name: Object Oriented Programming, OOP for short. A basic principle of OOP is that a computer program is composed of a single unit or object that can function as a subroutine. OOP achieves the three main goals of software engineering: reusability, flexibility, and scalability. OOP=object+class+inheritance+polymorphism+message, the core concept is class and object.
This passage often appears when introducing object-oriented programming on the Internet. Most Go
language should also be transferred from C++
, python
, java
, so the understanding of object-oriented programming should be very deep, so this article There is no need to introduce the concept, let's focus on how to use the Go
language to realize the programming style of object-oriented programming.
kind
Go
language itself is not an object-oriented programming language, so Go
is no concept of classes in the 0619074bbb9488 language, but it supports types, so we can use the struct
type to provide services similar java
, which can define attributes and methods , You can also define the constructor. Let's look at an example:
type Hero struct {
Name string
Age uint64
}
func NewHero() *Hero {
return &Hero{
Name: "盖伦",
Age: 18,
}
}
func (h *Hero) GetName() string {
return h.Name
}
func (h *Hero) GetAge() uint64 {
return h.Age
}
func main() {
h := NewHero()
print(h.GetName())
print(h.GetAge())
}
This is a simple "class" use. The class name is Hero
, where Name
and Age
are the attributes we define, GetName
and GetAge
are the methods of the class we define, and NewHero
is the defined constructor. Because Go
language, the constructor can only be implemented manually by us.
The realization of the method here depends on the characteristics of the value receiver and pointer receiver of the structure.
Encapsulation
Encapsulation is to privatize the properties of an object, while providing some properties and methods that can be accessed by the outside world. If we don't want to be accessed by the outside world, we don't need to provide methods for outside access. To achieve encapsulation in the Go
language, we can use two ways:
Go
language supports package-level encapsulation. Names starting with lowercase letters can only be visible in the program in the package, so if we don’t want to expose some methods, we can private the contents of the package in this way. This understanding is relatively simple, so we won’t mention it. Example.Go
language cantype
keyword, so in order not to expose some properties and methods, we can create a new type and implement encapsulation by handwriting the constructor by ourselves, for example:
type IdCard string
func NewIdCard(card string) IdCard {
return IdCard(card)
}
func (i IdCard) GetPlaceOfBirth() string {
return string(i[:6])
}
func (i IdCard) GetBirthDay() string {
return string(i[6:14])
}
Declare a new type IdCard
, is essentially a string
type, NewIdCard
used to construct the object,
GetPlaceOfBirth
and GetBirthDay
are encapsulation methods.
inherit
Go
does not have native-level inheritance support, but we can use a combination to achieve inheritance, through the structure of the embedded type to achieve inheritance, typical applications are embedded anonymous structure type and embedded anonymous interface type, these two There is a slight difference in this method:
- Embedded anonymous structure type: The parent structure is embedded in the substructure. The substructure has the properties and methods of the parent structure, but this method cannot support parameter polymorphism.
- Embedded anonymous interface type: The interface type is embedded in the structure, which implements all the methods of the interface by default. The structure can also rewrite these methods. This method can support parameter polymorphism. One point to note is that if the embedded type does not implement all interface methods, it will cause an undetected runtime error at compile time.
Example of implementing inheritance of embedded anonymous structure type
type Base struct {
Value string
}
func (b *Base) GetMsg() string {
return b.Value
}
type Person struct {
Base
Name string
Age uint64
}
func (p *Person) GetName() string {
return p.Name
}
func (p *Person) GetAge() uint64 {
return p.Age
}
func check(b *Base) {
b.GetMsg()
}
func main() {
m := Base{Value: "I Love You"}
p := &Person{
Base: m,
Name: "asong",
Age: 18,
}
fmt.Print(p.GetName(), " ", p.GetAge(), " and say ",p.GetMsg())
//check(p)
}
The method commented out above proves that parameter polymorphism cannot be performed.
Examples of embedded anonymous interface type implementation inheritance
Take a business scenario as an example. Assuming that we now want to send a notification to the user, the web
app
is the same, but the actions after clicking are different, so we can abstract an interface OrderChangeNotificationHandler
To declare three public methods: GenerateMessage
, GeneratePhotos
, generateUrl
, all classes will implement these three methods, because web
and app
ends is the same, so we can extract a parent class OrderChangeNotificationHandlerImpl
to implement a default Method, and then write two subclasses WebOrderChangeNotificationHandler
and AppOrderChangeNotificationHandler
to inherit the parent class and override the generateUrl
method. If the content of different ends is modified later, just rewrite the parent class method directly. Let’s look at the example:
type Photos struct {
width uint64
height uint64
value string
}
type OrderChangeNotificationHandler interface {
GenerateMessage() string
GeneratePhotos() Photos
generateUrl() string
}
type OrderChangeNotificationHandlerImpl struct {
url string
}
func NewOrderChangeNotificationHandlerImpl() OrderChangeNotificationHandler {
return OrderChangeNotificationHandlerImpl{
url: "https://base.test.com",
}
}
func (o OrderChangeNotificationHandlerImpl) GenerateMessage() string {
return "OrderChangeNotificationHandlerImpl GenerateMessage"
}
func (o OrderChangeNotificationHandlerImpl) GeneratePhotos() Photos {
return Photos{
width: 1,
height: 1,
value: "https://www.baidu.com",
}
}
func (w OrderChangeNotificationHandlerImpl) generateUrl() string {
return w.url
}
type WebOrderChangeNotificationHandler struct {
OrderChangeNotificationHandler
url string
}
func (w WebOrderChangeNotificationHandler) generateUrl() string {
return w.url
}
type AppOrderChangeNotificationHandler struct {
OrderChangeNotificationHandler
url string
}
func (a AppOrderChangeNotificationHandler) generateUrl() string {
return a.url
}
func check(handler OrderChangeNotificationHandler) {
fmt.Println(handler.GenerateMessage())
}
func main() {
base := NewOrderChangeNotificationHandlerImpl()
web := WebOrderChangeNotificationHandler{
OrderChangeNotificationHandler: base,
url: "http://web.test.com",
}
fmt.Println(web.GenerateMessage())
fmt.Println(web.generateUrl())
check(web)
}
Because all combinations implement the OrderChangeNotificationHandler
type, it can handle any specific type and wildcards that are derived from that specific type.
Polymorphism
Polymorphism is the essence of object-oriented programming. Polymorphism is the ability of the code to take different behaviors according to the specific realization Go
language can implement any interface, so the interface value method through different entity types The call is polymorphism, for example:
type SendEmail interface {
send()
}
func Send(s SendEmail) {
s.send()
}
type user struct {
name string
email string
}
func (u *user) send() {
fmt.Println(u.name + " email is " + u.email + "already send")
}
type admin struct {
name string
email string
}
func (a *admin) send() {
fmt.Println(a.name + " email is " + a.email + "already send")
}
func main() {
u := &user{
name: "asong",
email: "你猜",
}
a := &admin{
name: "asong1",
email: "就不告诉你",
}
Send(u)
Send(a)
}
Summarize
In the final analysis, object-oriented programming is a kind of programming idea, but some languages provide better support for this idea in terms of grammatical characteristics. It is easier to write object-oriented code, but we still write the code, not what we use After java
will definitely write more abstract code. In my work, I see that there are java
procedural codes written with 0619074bbb97c7. So no matter what language we use, we should think about how to write a good code, a lot of Abstract interfaces help us streamline the code. The code is elegant, but we also face readability issues. Everything has two sides. The road to writing good code is still a long way, and we need to continue to explore... ........
The sample code in the article has been uploaded github
: https://github.com/asong2020/Golang_Dream/tree/master/code_demo/oop
Welcome to pay attention to the public account: Golang DreamWorks
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。