• 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
    
  • 相关阅读:
    16进制节码解析
    批注:modbus_tkdefines.py
    <20211019> Win10不明原因丢失任务提示栏里的Wifi以及网络任务提示栏logo
    <20210926>log: 运行5年3个月的NAS硬盘更换
    Huggingface中的BERT模型的使用方法
    list变量和dict变量前面加*号
    Linux服务器登录阿里网盘下载和上传文件的方法
    【IDEA与git集成】
    【为什么要用 @param注解】
    【我的编程习惯与开发插件】
  • 原文地址:https://www.cnblogs.com/maomaomaoge/p/14129422.html
Copyright © 2020-2023  润新知