In the previous tutorial, I have already introduced that Go language, unlike object-oriented programming languages such as Java and PHP, does not support keywords like class
to define classes. Instead, it uses the type
keyword combined with basic types or structures to define the type system. Additionally, it does not support explicitly defining inheritance relationships between types using the extends
keyword.
This article is first published in the medium MPP plan. If you are a medium user, please follow me in medium. Thank you very much.
Strictly speaking, Go language is not an object-oriented programming language, at least not the best choice for object-oriented programming (Java is the most established one). However, we can simulate object-oriented programming based on some features provided by Go.
To implement object-oriented programming, we must implement the three major features of object-oriented programming: encapsulation, inheritance, and polymorphism.
Inheritance
Next is inheritance. Although Go does not directly provide syntax for inheritance, we can indirectly achieve similar functionality through composition. Composition means embedding one type into another type to build a new type structure.
In traditional object-oriented programming, explicitly defining inheritance relationships has two drawbacks: one is that it leads to increasingly complex class hierarchies, and the other is that it affects the extensibility of classes. Many software design patterns advocate using composition instead of inheritance to improve class extensibility.
Let's take an example. Suppose we want to create a UI component library. We have a Widget
structure type with two properties, x
and y
, representing the length and width of the component.
If we want to define a class representing Label
, we can do it like this:
type Label struct {
Widget
text string
}
Here, Label
inherits all the properties of Widget
and adds a new property text
. Similarly, we can define the Button
and ListBox
classes:
type Button struct {
Label
}
type ListBox struct {
Widget
text []string
index int
}
Polymorphism
First, we define two interfaces, Painter
for painting and Clicker
for clicking:
type Painter interface {
Paint()
}
type Clicker interface {
Click()
}
Then, the components implement these interfaces:
func (label Label) Paint() {
// display label
fmt.Printf("%p:Label.Paint(%q)\n", &label, label.text)
}
func (button Button) Paint() {
// display button
fmt.Printf("Button.Paint(%q)\n", button.text)
}
func (button Button) Click() {
// click button
fmt.Printf("Button.Click(%q)\n", button.text)
}
func (listBox ListBox) Paint() {
// display listBox
fmt.Printf("ListBox.Paint(%q)\n", listBox.text)
}
Label
implements Painter
, and Button
and ListBox
implement both Painter
and Clicker
.
At the application level, we can use these components like this:
label := Label{Widget{10, 10}, "State:"}
button1 := Button{Label{Widget{10, 70}, "OK"}}
button2 := NewButton(50, 70, "Cancel")
listBox := ListBox{Widget{10, 40},
[]string{"AL", "AK", "AZ", "AR"}, 0}
for _, painter := range []Painter{label, listBox, button1, button2} {
painter.Paint()
}
fmt.Println("=========================================")
for _, clicker := range []Clicker{listBox, button1, button2} {
clicker.Click()
}
fmt.Println("=========================================")
for _, widget := range []interface{}{label, listBox, button1, button2} {
widget.(Painter).Paint()
if clicker, ok := widget.(Clicker); ok {
clicker.Click()
}
}
Go language is different from object-oriented programming languages like Java and PHP in that it does not provide keywords specifically for referencing parent class instances (such as super
, parent
, etc.). In Go language, the design philosophy is simplicity, without any unnecessary keywords. All calls are straightforward.
Summary
Let's summarize briefly. In Go language, the concept of classes in traditional object-oriented programming is intentionally weakened, which is in line with Go's philosophy of simplicity. The "classes" defined based on structures are just ordinary data types, similar to built-in data types. Built-in data types can also be transformed into "classes" that can contain custom member methods using the type
keyword.
All methods associated with a data type collectively form the method set of that type. Like other object-oriented programming languages, methods within the same method set cannot have the same name. Additionally, if they belong to a structure type, their names cannot overlap with any field names in that type.