-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathbase.go
More file actions
120 lines (113 loc) · 3.37 KB
/
base.go
File metadata and controls
120 lines (113 loc) · 3.37 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
// Package base describes the Base struct, which provides virtual functions and inheritance similar to
// that of C++ and Java.
package base
import (
"reflect"
)
// Base is a base structure to embed in objects so that it can call its functions as virtual functions.
// It provides support for a pattern of inheritance that is similar to C++ or Java.
//
// Virtual functions are functions that provide a default implementation but that can be overridden by a subclass.
// This is generally thought of as an anti-pattern in Go, but for certain applications, it can be really
// useful.
//
// Every structure that needs to call a virtual function will require a matching interface that defines the
// virtual functions to be called.
//
// Example:
//
// // Bird is the base class of all birds.
// type Bird struct {
// Base
// }
//
// // BirdI defines the virtual functions of Bird.
// type BirdI interface {
// BaseI
// Call() string
// }
//
// func NewBird() *Bird {
// b := new(Bird)
// b.Init(b)
// return b
// }
//
// func (a *Bird) PrintCall () {
// fmt.Print(a.this().Call())
// }
//
// // Call here is the default implementation that can be overridden by a subclass.
// func (a *Bird) Call () string {
// return "chirp"
// }
//
// // this returns a BirdI interface whose functions will be the overriden functions of subclasses.
// func (a *Bird) this() BirdI {
// return a.Self().(BirdI)
// }
//
// type Duck struct {
// Bird
// }
//
// type DuckI interface {
// BirdI
// }
//
// func NewDuck() *Duck {
// d := new(Duck)
// d.Init(d) // must initialize the base class with the new object
// return d
// }
//
// func (a *Duck) Call () string {
// return "quack"
// }
//
// The following code will then print "quack":
//
// NewDuck().PrintCall()
//
// while the following code will the print "chirp".
//
// NewBird().PrintCall()
//
// Be careful when using GobDecode() to restore an encoded object. To restore virtual function ability, you should
// call Init() on the object after it is decoded.
type Base struct {
self any
}
// Init captures the object being passed to it so that virtual functions can be called on it.
func (b *Base) Init(self any) {
if b.self != nil && b.self != self {
panic("do not initialize an object twice")
}
b.self = self
}
// Self returns the self as an interface object.
func (b *Base) Self() any {
return b.self
}
// TypeOf returns the reflection Type of self.
func (b *Base) TypeOf() reflect.Type {
return reflect.Indirect(reflect.ValueOf(b.self)).Type()
}
// String implements the Stringer interface.
//
// This default functionality outputs the object's type. String is overridable.
func (b *Base) String() string {
return b.TypeOf().String()
}
// BaseI is an interface representing all objects that embed the Base struct.
//
// It adds the ability for all such objects to get the object's type and a string
// representation of the object, which by default is the object's type. To be sure
// to get the object's type even if String() is overridden, use TypeOf().String().
type BaseI interface {
// TypeOf returns the reflection type of the object. This allows superclasses to determine
// the type of the subclassing object. The type will not be a pointer to the type, but the type itself.
TypeOf() reflect.Type
// String returns a string representation of the object.
String() string
}