学过php的同学,都使用过继承,golang引入了组合,接下来我们聊下继承和组合的区别。
一、继承与组合
1、 继承的特点
- 子类继承父类,拥有了父类的属性和方法
<?php
class Base {
public $attrA = "class Base,attrA";
public function methodA(){
return "class Base,methodA";
}
}
class Child extends Base{
}
$obj = new Child();
var_dump($obj->attrA);
var_dump($obj->methodA());
输出结果:
string(16) "class Base,attrA"
string(18) "class Base,methodA"
- 可以重新定义父类方法和属性
<?php
class Base {
public $attrA = "class Base,attrA";
public function methodA(){
return "class Base,methodA";
}
}
class Child extends Base{
public $attrA = "class Child,attrA";
public function methodA(){
return "class Child,methodA";
}
}
$obj = new Child();
var_dump($obj->attrA);
var_dump($obj->methodA());
输出结果
string(17) "class Child,attrA"
string(19) "class Child,methodA"
- 可以拥有子类自己的方法和属性
<?php
class Base {
public $attrA = "class Base,attrA";
public function methodA(){
return "class Base,methodA";
}
}
class Child extends Base{
public $attrB = "class Child,attrB";
public function methodB(){
return "class Child,methodB";
}
}
$obj = new Child();
var_dump($obj->attrB);
var_dump($obj->methodB());
输出结果:
string(17) "class Child,attrB"
string(19) "class Child,methodB"
- 父类方法可以获取子类属性值,也可以调用子类的方法(
这与组合不同)
<?php
class Base {
public $attrA = "class Base,attrA";
public function GetAttrA(){
return $this->attrA;
}
public function MethodA(){
return "class Base,MethodA";
}
public function GetMethodA(){
return $this->MethodA();
}
}
class Child extends Base{
public $attrA = "class Child,attrA";
public function MethodA(){
return "class Child,MethodA";
}
}
$obj = new Child();
var_dump($obj->attrA);
var_dump($obj->GetAttrA());
var_dump($obj->GetMethodA());
输出结果
string(17) "class Child,attrA"
string(17) "class Child,attrA"
string(19) "class Child,MethodA"
2、组合
- 当前类的实例可以访问被组合类的属性和方法,且可以给被组合类属性赋值
package main
import "fmt"
type Base struct {
AttrA interface{}
}
func (m *Base) MethodA() interface{} {
return "class Base,MethodA"
}
type Child struct {
Base
}
func NewChild() *Child {
return new(Child)
}
func main() {
obj := NewChild()
obj.AttrA = "method main,AttrA"
fmt.Println(obj.AttrA)
fmt.Println(obj.MethodA())
}
输出结果
method main,AttrA
class Base,MethodA
- 如果存在当前类的方法、属性和被组合类的方法、属性重名,那么当前类的实例只能访问当前类的方法和属性
package main
import "fmt"
type Base struct {
AttrA interface{}
}
func (m *Base) MethodA() interface{} {
return "class Base,MethodA"
}
type Child struct {
Base
AttrA interface{}
}
func (m *Child) MethodA() interface{} {
return "class Child,MethodA"
}
func NewChild() *Child {
return &Child{AttrA: "class Child,AttrA"}
}
func main() {
obj := NewChild()
fmt.Println(obj.AttrA)
fmt.Println(obj.MethodA())
}
输出结果
class Child,attrA
class Child,MethodA
- 当前类可以拥有自己的方法和属性
package main
import "fmt"
type Base struct {
AttrA interface{}
}
func (m *Base) MethodA() interface{} {
return "class Base,MethodA"
}
type Child struct {
Base
AttrB interface{}
}
func (m *Child) MethodB() interface{} {
return "class Child,MethodB"
}
func NewChild() *Child {
return &Child{AttrB: "class Child,AttrB"}
}
func main() {
obj := NewChild()
fmt.Println(obj.AttrB)
fmt.Println(obj.MethodA())
}
输出结果
class Child,AttrB
class Base,MethodA
- 被组合类的方法中无法访问当前类的方法和属性
ackage main
import "fmt"
type Base struct {
AttrA interface{}
}
func (m *Base) MethodA() interface{} {
return "class Base,MethodA"
}
func (m *Base) GetAttrA() interface{} {
return m.AttrA
}
func (m *Base) GetMethodA() interface{} {
return m.MethodA()
}
type Child struct {
Base
AttrA interface{}
}
func (m *Child) MethodA() interface{} {
return "class Child,MethodA"
}
func NewChild() *Child {
return &Child{AttrA: "class Child,AttrB"}
}
func main() {
obj := NewChild()
fmt.Println(obj.GetAttrA())
fmt.Println(obj.GetMethodA())
}
输出结果
<nil>
class Base,MethodA
结论
-
继承表示两个类是有父子关系,父类的方法和属性被子类继承了,那相当于父类的方法就是子类的方法,所以在父类方法中调用子类属性和方法相当于子类调用子类的方法属性。
-
组合表示两个类是组合关系,当前类可以访问被组合类的方法和属性,也可以给被组合类属性赋值,但是这些方法和属性仍然是被组合类的,当前类创建的方法和属性是当前类,被组合类无法访问。
举一个实际业务使用的场景
有一个Base类,我们想使用Base类的Query方法,但是要是Query要查询我自己的表,下面是实现方案。
package main
import "fmt"
type Base struct {
TableName string
}
func (m *Base) Query() interface{} {
return "select * from " + m.TableName
}
type model struct {
Base
}
func NewModel() *model {
obj := new(model)
obj.TableName = "tableA"
return obj
}
func main() {
obj := NewModel()
fmt.Println(obj.TableName)
fmt.Println(obj.Query())
}
输出结果
tableA
select * from tableA