golang学习笔记(6)--面向接口编程

一、    duck typing

duck typing意思是鸭子类型,我们把具备鸭子的行为等部分特征的一个东西叫做鸭子,这是鸭子类型的解释。其实,在go语言中是采用鸭子类型这种思想来实现接口这种编程方式的,我们把一个类只要实现了某接口的方法,我们就说他是这个接口的实现类。如下:

我们定义了一个接口:

type duck interface {
   Get(s string) string //不用func修饰这个方法
}

下面写一个类:
type TheClass struct {
   S string
}
这个类实现了上面接口中的方法,如下,并不需要声明我们要实现某个接口。
func (tc TheClass) Get(s string) string  {
   return tc.S;
}

实现类前面的类型是属于值类型传递,因为我们的接口里面实际是包了一个类型信息与及指针,所以实现一般采用直接的值传递而不是指针传递,因为一样可以对内容修改。

如上通过go语言的方式来说明了什么是鸭子类型。

二、    go语言中的接口。

上面讲过了接口的实现方式。

type duck interface {
   Get(s string) string
}

之前我们有讲过两种go语言的两种“继承“方式,一种是类似于装饰的叫做组合,在类里面放”父类“,另一种是取别名,当然取别名算不上,他不可以增加成员变量。那么接口可以”继承“吗?嗯,当然可以,如下

type littleDuck interface {
duck
A() string
}
这样应该叫接口的“继承”
刚刚在golang社区看到一篇被喷的文章,下面有个人这样说:“golang的接口是非入侵式的,楼主让非得把(**)接口写入到(**)结构中,真是人才啊“
不是很理解什么意思,难道不能够用接口继承吗?问题先留在这里,以后再解决。
(n分钟过后)
查了下什么叫入侵式与非入侵式,附上自己的理解:入侵式是指要申明接口实现了某一个接口什么的,但是非入侵式就不用,一般的oo语言例如java就是入侵式接口设计,需要说明实现,有层级,但是go语言提倡是非入侵式,相对入侵式可能更灵活一点,不那么多依赖,但是这两种设计都各有优点,什么优点?看完下面的就知道了,接下来用例子来说下自己的理解吧。
à: 
Bird 接口 : fly(),run();
Chicken 接口 : run()
Wild 接口 :fly()
如上3个接口,在入侵式接口设计中,chicken接口与wild接口需要去继承bird接口,因为他们属于这个大类,那么我们创建一个chicken的实现类对象的话,只需要实现chicken,然后wild同理。这样做就是入侵式接口设计的思路。
在java中像这样:
interface Bird{
void run();
void fly();
}
interface Wild extends Bird{
void run();
}
interface Chicken extends Bird{
void fly();
}
如果我们想要创建一个Wild的类型的类那么就需要创建一个,需要给wild写个实现类,一个Chicken类型的类就需要写一个Chicken实现类,Bird就需要写一个Bird的实现类,显然接口的复用性不高。当然这样的类型是相当清晰的。
同样有另外一种写法,这样算是入侵式设计的思想,如下:
interface Run{
void run();
}
interface Fly{
void fly();
}

interface Bird1 extends Run,Fly{}
java的接口继承是支持多继承的
这样的写法是一种组装的思想,这也是oo语言中的入侵式接口设计思路,通过继承的方式组装好,然后去写Bird1的实现类,没什么问题。
再看看非入侵式:go语言推荐使用非入侵式接口设计,在写实现类的时候不需要说明实现哪个接口,也不需要去思考这是哪个接口的实现类,只要实现相应的方法就行,一般推荐这样写:
type chicken interface {
run()
}
type wild interface {
fly()
}
type BirdImpl struct {
}
func (b BirdImpl) run()  {
}
func (b BirdImpl) fly(){
}
如上的方式很灵活,我们直接可以birdImpl创建一个类,然后实现一个方法他就属于某一个类型,不用去组装接口。当然,我们也可以通过实现接口的方式来实现接口,如:
type Bird interface {
run()
fly()
}
type chicken interface {
run()
}
type wild interface {
fly()
}
这样的方式相当于bird实现了两个接口的接口,我要创建实体对象的时候需要再创建一个类:
type BirdImpl struct {}
func (b BirdImpl) run(){}
func (b BirdImpl) fly(){}
这个类从这里看必定就实现了上述的3个接口,这样的写法其实是可以的,但是看起来冗余了许多,我完全可以不需要Bird 或者另外两个接口。Go语言这样的接口设计方式相对更简单、灵活了。当然为了更具解释性,我们可以把wild名改成Fly,chicken改成Run。当然这样的组合方式在go语言使用还是不少,因为通过组合的方式也很方便灵活
那么我们可以这样来设计go语言的接口:
type Bird interface {
run()
fly()
}
type BirdImpl struct {}
func (b BirdImpl) run()  {}
func (b BirdImpl) fly(){}
或者这样:
type Run interface {
run()
}
type Fly interface {
fly()
}
type BirdImpl struct {}
func (b BirdImpl) run()  {}
func (b BirdImpl) fly(){}
这样就是非入侵式接口设计,不在接口使用继承。好像最后总结下爱就这么一句话,不在接口关系中使用继承与及接口实现。
 刚刚留了一个问题,入侵式与非入侵式的比较,从上面也可以看到入侵式接口设计类别层级什么的十分清晰,没有那么多依赖,解释性也比较好。非入侵式呢?相对比较灵活,简单,接口复用率高。(这都是我的理解哈,不代表官方说法)
网上对入侵式与非入侵式的观点很多,以上只是我的理解,而且go语言的源码里面也有很多组合接口的地方,我也很难说,这两个概念就先放一放。
三、               接口的使用。
首先说下接口变量的结构,其内部有两个东西,一个是接口实现者的类型,一个是接口实现者的指针,我们来看一段段代码:
var o A
 o = class.B{}
 fmt.Printf("%T,%p",o,o)
这里的B实现了接口A,T是类型,v是值,可以知道o里面实际含有两个人东西。同时要提下,如果在不同包下进行接口实现,记住大写方法名首字母,这样才是public的。
接下来我们讲下接口的组合,上面讲到接口的组合不被推荐,说法是有问题的,通过后面的学习,接口是可以被组合的,而且在go的源码中还大量被用到,这种组合的方式是很方便的,当然存在的问题也是问题,这个就不去争议了,网上观点不一。
接口的组合上文已经讲过了,这里我们来讲讲interface{},interface{}代表go语言里面的所有类型,意义和java的Object一样,但是go不是说所有类都继承interface,没有这种说法:
i := [...]interface{}{1,"2",3,"a","v"}
 fmt.Println(i)
如上代码,数组元素可以是任意类型,当然可以作为函数传入值类型的时候,就表示可以传入任意类型。
四、               Go两种常用接口。
a)  stringer
这个接口相当与java的toString()方法,我们只要实现string()string方法,就算是实现了这个接口,直接打印对象的时候自动调用string。
func (b B) String() string {
  return "实现了stringer的B"
}
比如这样写。
b)  reader/writer
file其实是实现了reader与writer两个接口的,一般我们需要reader或者writer实例的时候可以传一个file进去也是一样的 ,这里可以用组合
type file interface{
Reader
Writer
}
 

转载于:https://www.cnblogs.com/luohuayu/p/9197894.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/366734.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

c语言self用法,C/C++知识点之Self Numbers C语言 UVA640

本文主要向大家介绍了C/C知识点之Self Numbers C语言 UVA640,通过具体的内容向大家展示,希望对大家学习C/C知识点有所帮助。In 1949 the Indian mathematician D.R. Kaprekar discovered a class ofnumbers called self-numbers. For any positive integ…

JS 的平凡之路--学习人气眼中的效果(上)

最近看了看人气眼的界面,感觉到学习的地方有很多呀。这里先带大家看看人气值跳动的实现。本篇代码基于Vue2.x.x。 一、概要 首先看一下效果图: 要想实现上面的效果,我们分为这几个部分: 判断元素是否在可视区域内;函数…

[Swift]LeetCode86. 分隔链表 | Partition List

★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★➤微信公众号:山青咏芝(shanqingyongzhi)➤博客园地址:山青咏芝(https://www.cnblogs.com/strengthen/)➤GitHub地址&a…

XmlNode与XmlElement的区别总结

原文链接:http://www.cnblogs.com/oilsun/archive/2012/07/07/2580427.html 今 天在做ASP.NET操作XML文档的过程中,发现了两个类:XmlNode和XmlElement。这两个类的功能极其类似(因为我们一般都是在对 Element节点进行操作&#xf…

HOW TO:构造Java类

在这篇HowTo帖子中,我将展示如何将一个类与另一个类一起定型。 为什么这有用? 当您的项目中发生大量BCI时,让每个开发人员编写BCI代码都是不明智的。 首先,这不会抽象出所使用的BCI库。 鉴于Java不支持多重继承,构造型…

android horizontalscrollview 动画,Android HorizontalScrollView左右滑动效果

本文实例为大家分享了Android HorizontalScrollView左右滑动的具体代码,供大家参考,具体内容如下效果图一.什么是HorizontalScrollViewHorizontalScrollView实际上是一个FrameLayout ,这意味着你只能在它下面放置一个子控件 ,这个子控件可以包…

[译] Airbnb 在 React Native 上下的赌注(一):概述

原文地址:React Native at Airbnb原文作者:Gabriel Peal译文出自:掘金翻译计划本文永久链接:https://github.com/xitu/gold-miner/blob/master/TODO1/react-native-at-airbnb.md译者:ALVINYEH校对者:ChenDo…

noip退役之路--祝福

原文地址:bb机的老巢 文/鲁迅 noip前的集训毕竟最像集训,去北京不必说,就在自己学校的机房中也显出将到noip的气象来。屏幕广播里讲解的题目闪着斑白的微光,随着鼠标叩击“提交”按钮的一声钝响,是直播ac后的欢呼&…

批处理最佳做法

大多数应用程序至少具有一个批处理任务,在后台执行特定的逻辑。 编写批处理作业并不复杂,但是您需要了解一些基本规则,我将列举一些我发现最重要的规则。 从输入类型的角度来看,处理项目可以通过轮询处理项目存储库来实现&#x…

android 360度视频播放器,Android开发VR实战之播放360度全景视频

VR即Virtual Reality虚拟现实。虚拟现实技术是一种可以创建和体验虚拟世界的计算机仿真系统它利用计算机生成一种模拟环境是一种多源信息融合的交互式的三维动态视景和实体行为的系统仿真使用户沉浸到该环境中。那么,如何在Android中去开发VR功能的APP呢&#xff1f…

关于怎么在手机端实现一个拖拽的操作

手机端&#xff0c;肯定是监听touchstart,touchmove,touchend事件 先来看看效果 当拖拽时&#xff0c;拖拽到哪个节点下面&#xff0c;就把哪个节点添加到这个下面 <div>1111</div><div>2222</div><div>3333</div><div>4444</div…

二叉树的前序创建

1 #include <stdio.h>2 #define ElemType char3 //节点声明&#xff0c;数据域、左孩子指针、右孩子指针4 typedef struct BiTNode{5 char data;6 struct BiTNode *lchild,*rchild;7 }BiTNode,*BiTree;8 //先序建立二叉树9 BiTree CreateBiTree(){ 10 char c…

Apache Karaf遇到Apache HBase

介绍 Apache HBase是模仿Google Bigtable的开源&#xff0c;分布式&#xff0c;版本化&#xff0c;面向列的商店。 如果您是普通读者&#xff0c;那么您可能已经知道Apache Karaf是什么&#xff0c;但是对于那些不是的读者&#xff1a;Apache Karaf是一个OSGi运行时&#xff0c…

物联网架构成长之路(24)-Docker练习之Compose容器编排

0.前言  一开始学的之后&#xff0c;是想一步到位直接上Kubernetes(K8s)的&#xff0c;后面没想到&#xff0c;好像有点复杂&#xff0c;有些概念不是很懂。因此学习东西还是要循序渐进&#xff0c;慢慢来。先了解单机编排技术Docker Compose&#xff0c;了解一些技术细节及原…

CSS原理解析之模型篇

写在前面&#xff1a;尝试回答几个问题&#xff1a;什么是盒模型&#xff0c;控制盒模型的属性有哪些&#xff1f;Margin、Padding、Border、Width、Height这些属性改变/影响盒模型&#xff0c;但每个属性都会在所有元素上生效么&#xff1f;如果存在区别&#xff0c;那么和元素…

Quartz遇到的问题

本文首次发布于My Blog,作者张琦(Ian),转载请保留原文链接。 有状态和无状态 使用有状态&#xff08;StatefulJob&#xff09;还是无状态的任务&#xff08;Job&#xff09; 在 Quartz 中&#xff0c;基本来说&#xff0c;任务分为有状态和无状态两种。实现 Job 接口的任务缺省…

android baseactivity,Android应用开发Android通过BaseActivity获取到当前启动的Activity名称...

本文将带你了解Android应用开发Android通过BaseActivity获取到当前启动的Activity名称&#xff0c;希望本文对大家学Android有所帮助。<在BaseActivity的onCreate方法中:public class BaseActivity extends AppCompatActivity { Override protected void onCreate(Nul…

RIP RETE时间获得PHREAKY

我刚刚完成了我称为PHREAK的新规则算法的一些高级文档&#xff0c;这是混合推理中的一个文字游戏。 它仍然有点粗糙和高水平&#xff0c;但希望仍然很有趣。 它建立在ReteOO之上&#xff0c;非常好阅读。 ReteOO算法 ReteOO是在3、4和5系列发行版中开发的。 它采用RETE算法并应…

Hadoop自学笔记(三)MapReduce简单介绍

1. MapReduce Architecture MapReduce是一套可编程的框架&#xff0c;大部分MapReduce的工作都能够用Pig或者Hive完毕。可是还是要了解MapReduce本身是怎样工作的&#xff0c;由于这才是Hadoop的核心&#xff0c;而且能够为以后优化和自己写做准备。 Job Client, 就是用户 Job …

洛谷 P2051 [AHOI2009]中国象棋 解题报告

P2051 [AHOI2009]中国象棋 题目描述 这次小可可想解决的难题和中国象棋有关&#xff0c;在一个N行M列的棋盘上&#xff0c;让你放若干个炮&#xff08;可以是0个&#xff09;&#xff0c;使得没有一个炮可以攻击到另一个炮&#xff0c;请问有多少种放置方法。大家肯定很清楚&am…