InterfaceSummary接口小结

InterfaceSummary接口小结

继承

注意: 其实这个和接口没多大关系,结构体实现,为了和实现接口做对比,但是还是要放在这里

​ 场景: 所有的程序员都有格子衫,有一个叫mike的普通程序员也是如此。但是有个牛逼的程序员mao,他还会骑 自行 车,也就是运动员的运动。

实现代码

# nest.go文件

package nest

import "fmt"

// 所有程序员的特质: 格子衫
type CommonProgrammer struct {
	Name string
}

// 所有程序员都有的特质: 格子衫
func (p *CommonProgrammer) commonHave() {
	fmt.Println(p.Name, "有格子衫")
}

// 一个叫maomao的程序员还会骑车
type MaoProgrammer struct {
	CommonProgrammer
	Biking string
}

func (m *MaoProgrammer) PrintSkill() {
	fmt.Println(m.Name, "还会", m.Biking)
}

func TestMain() {
	// 先初始化一个普通程序员
	mike := CommonProgrammer{}
	mike.Name = "mike"
	mike.commonHave()

	// 特殊技能程序员
	maomao := MaoProgrammer{}
	maomao.Name = "mao"
	maomao.Biking = "骑车"
	maomao.commonHave()
	maomao.PrintSkill()
}

测试

# nest_test.go文件
package nest

import "testing"

func TestTestMain(t *testing.T) {
	TestMain()
}
# 输出
mike 有格子衫 
mao 有格子衫
mao 还会 骑车

实现接口

对于以上的自行车运动,这样看起来并不好,假如有其他分类,看着不是很规范,我们又不想破坏程序员继承关系,又想拓展其他方面,这时候我们就需要接口了

代码实现

package real

import "fmt"

// 声明运动员接口
type Sporter interface {
	Biking()
}

// 所有程序员的特质: 格子衫
type CommonProgrammer struct {
	Name string
}

func NewCommonProgrammer(n string) CommonProgrammer {
	return CommonProgrammer{Name:n}
}

// 所有程序员都有的特质: 格子衫
func (p *CommonProgrammer) commonHave() {
	fmt.Println(p.Name, "有格子衫")
}


// 一个叫maomao的程序员还会骑车
type MaoProgrammer struct {
	CommonProgrammer
}

func NewMaoProgrammer(n string) MaoProgrammer {
	return MaoProgrammer{CommonProgrammer{Name:n}}
}

func (m *MaoProgrammer) Biking() {
	fmt.Println(m.Name, "还会骑自行车")
}

func TestIntesrface(S Sporter) {
	fmt.Println("我是主要测试")
	S.Biking()
	fmt.Println("这里证明了结构体实现了接口的所有方法,就是这个接口")
}

func TestMain() {
	// 先初始化一个普通程序员
	mike := NewCommonProgrammer("mike")
	mike.commonHave()

	// 特殊技能程序员

	maomao := NewMaoProgrammer("mao")
	maomao.commonHave()
	var i Sporter

	// 注意这里的取地址
	i = &maomao
	TestIntesrface(i)
}

测试

package real

import "testing"

func TestTestMain(t *testing.T) {
	TestMain()
}

输出

mike 有格子衫
mao 有格子衫
我是主要测试
mao 还会骑自行车
这里证明了结构体实现了接口的所有方法,就是这个接口

小结

  • 接口和继承解决的问题不同

    ​ 继承在于解决代码的复用性和可维护性

    ​ 接口价值在于设计好规范

  • 接口比继承更加灵活

    接口满足like-a,继承需要是is-a

  • 接口在一定程度上实现代码解耦

附加

​ 责任链模式(设计模式,这里可以更加理解接口,我很喜欢这个大佬的实现,因为这个代码可以无限拓展,结 合了链表)

package main

import (
	"fmt"
)

// Context Context
type Context struct {
}

// Handler 处理
type Handler interface {
	// 自身的业务
	Do(c *Context) error
	// 设置下一个对象
	SetNext(h Handler) Handler
	// 执行
	Run(c *Context) error
}

// Next 抽象出来的 可被合成复用的结构体
type Next struct {
	// 下一个对象
	nextHandler Handler
}

// SetNext 实现好的 可被复用的SetNext方法
// 返回值是下一个对象 方便写成链式代码优雅
// 例如 nullHandler.SetNext(argumentsHandler).SetNext(signHandler)
func (n *Next) SetNext(h Handler) Handler {
	n.nextHandler = h
	return h
}

// Run 执行
func (n *Next) Run(c *Context) (err error) {
	// 由于go无继承的概念 这里无法执行当前handler的Do
	// n.Do(c)
	if n.nextHandler != nil {
		// 合成复用下的变种
		// 执行下一个handler的Do
		if err = (n.nextHandler).Do(c); err != nil {
			return
		}
		// 执行下一个handler的Run
		return (n.nextHandler).Run(c)
	}
	return
}

// NullHandler 空Handler
// 由于go无继承的概念 作为链式调用的第一个载体 设置实际的下一个对象
type NullHandler struct {
	// 合成复用Next的`nextHandler`成员属性、`SetNext`成员方法、`Run`成员方法
	Next
}

// Do 空Handler的Do
func (h *NullHandler) Do(c *Context) (err error) {
	// 空Handler 这里什么也不做 只是载体 do nothing...
	return
}

// ArgumentsHandler 校验参数的handler
type ArgumentsHandler struct {
	// 合成复用Next
	Next
}

// Do 校验参数的逻辑
func (h *ArgumentsHandler) Do(c *Context) (err error) {
	fmt.Println("任务0")
	return
}

// AddressInfoHandler 地址信息handler
type AddressInfoHandler struct {
	// 合成复用Next
	Next
}

// Do 校验参数的逻辑
func (h *AddressInfoHandler) Do(c *Context) (err error) {
	fmt.Println( "任务1...")
	return
}

func main() {
	// 初始化空handler
	nullHandler := &NullHandler{}

	// 链式调用 代码是不是很优雅
	// 很明显的链 逻辑关系一览无余
	nullHandler.SetNext(&ArgumentsHandler{}).
		SetNext(&AddressInfoHandler{})
	//无限扩展代码...

	// 开始执行业务
	nullHandler.Run(&Context{})
	// 成功
	fmt.Println("Success")
	return
}

输出

任务0
任务1...
Success
posted @ 2020-12-13 18:05  maob  阅读(174)  评论(0编辑  收藏  举报