面向接口

duck typing的概念

描述事物的外部行为而非内部结构。
在动态语言设计中,可以解释为无论一个对象是什么类型的,只要它具有某类型的行为(方法),则它就是这一类型,而不在于它是否显示的实现或者继承。

动态类型语言:是在运行时确定数据类型的语言,变量在使用之前不需要类型声明,通常变量的类型是被赋值的那个值的类型。如Python
静态类型语言:在编译时变量的数据类型就可以确定的语言。如C++

像C++一类的静态类型语言,传入的参数必须要是所要求的类型才行,要想表现出不同的行为,就得通过继承、多态等机制。

//python中的duck typing
//运行时才知道传入的retriver有没有get;需要注释来说明接口
def download(retriever):
	return retriever.get("www.imooc.com")

//C++中的duck typing
//编译时才知道传入的retriver有没有get;需要注释来说明接口
template <class R>
string download(const R& retriver){
	return retriever.get("www.imooc.com");
}

//java中的类似代码
//传入的参数必须实现Retriver接口;不是duck typing
//若一个类有get方法,但是没有实现Retriver接口,也不能给download用,因此不是duck typing
<R extends Retriver>
String download(R r){
	return r.get("www.imooc.com");
}

//go语言的duck typing
//什么类型都是穿,只要实现了get方法就可以;可以同时实现好几个接口;具有类型检查

接口

在面向对象编程中,可以这么说:“接口定义了对象的行为”, 那么具体的实现行为就取决于对象了。
在go语言中,接口就是一系列行为的集合。
接口的作用:1.如果你写了一个类, 一年后你对这个类不满意, 你想重新实现一个, 那为了保证兼容性, 你肯定不能完全写个新的对吧。则可以在刚开始写这个类的时候就想好这个类可以提供哪些方法, 然后定义一个接口, 然后一年后你写个新的, 你直接实现这个接口就好了。可以方便的进行修改和重构。2.var t Printer = &User{1, “Tom”} Printer是接口,User实现了Printer,因此这句话就可以实现了多态性。

接口由使用者定义。download(使用者)------>retriever(实现者)
实现者不需要声明实现了哪个接口,只要实现了其方法就行。由使用者规定这个Retriever必须有Get方法。

type Retriever interface {
	Get(url string) string
}
func download(r Retriever) string {
	return r.Get("http://www.imooc.com")
}

//接口是实现是隐式的,只要实现里面的方法。
// 一种实现
type Retrievers struct {
	Contents string
}
func (r Retrievers) Get(url string) string {
	return r.Contents
}
//另一种实现
type Retrievers struct {
}

func (r Retrievers) Get(url string) string {
	resp, err := http.Get(url)
	if err != nil {
		panic(err)
	}

	res, err := httputil.DumpResponse(resp, true)
	resp.Body.Close()

	if err != nil {
		panic(err)
	}
	return string(res)
}

func main() {
	var r Retriever
	//实现了多态
	r = mock.Retrievers{"this is a fake Retriever"}
	r = real.Retrievers{}
	fmt.Println(download(r))
}

接口的值类型

接口变量里面有什么?一个是实现者的类型,一个是实现者的值/实现者的指针。

r = &real.Retrievers{
		"Mozilla/5.0",
		time.Minute,
	}
fmt.Printf("%T, %v\n", r, r)
//*real.Retrievers &{Mozilla/5.0 1m0s}

r = mock.Retrievers{"this is a fake Retriever"}
fmt.Printf("%T, %v\n", r, r)
//mock.Retrievers, {this is a fake Retriever}

interface{}表示任何类型

package queue

type Queue []interface{}

func (q *Queue) Push(v interface{}) {
	*q = append(*q, v.(int)) 
}

func (q *Queue) Pop() int {
	head := (*q)[0]
	*q = (*q)[1:]
	return head.(int) //interface{}类型具体化为int类型
}

func (q *Queue) IsEmpty() bool {
	return len(*q) == 0
}

go语言的方法集。

从值的角度来看规则

Values	Methods Receivers
T	(t T)
*T	(t T) and (t *T)
T类型的值的方法集只包含值接收者声明的方法。而指向T类型的指针的方法集既包含值接收者声明的方法,也包含指针接收者声明的方法。

从接收者的角度来看规则

Methods Receivers	Values
(t T)	T and *T
(t *T)	*T

指针接收者实现只能以指针方式使用;值接收者都可以。
使用指针接收者来实现一个接口,那么只有指向那个类型的指针才能够实现对应的接口。如果使用值接收者来实现一个接口,那么那个类型的值和指针都能够实现对应的接口。
type assertion和type switch用法。


type Retriever interface {
	Get(url string) string
}

func download(r Retriever) string {
	return r.Get("http://www.imooc.com")
}
func main() {
	var r Retriever
	r = mock.Retrievers{"this is a fake Retriever"}
	//r = &mock.Retrievers{"this is a fake Retriever"}
	inspect(r)

	//type assertion
	mockRetriever := r.(mock.Retrievers)
	fmt.Println(mockRetriever.Contents)
	
	/*
	type Retrievers struct {
		UserAgent string
		TimeOut   time.Duration
	}
	//使用指针接收者
	func (r *Retrievers) Get(url string) string {}*/
	r = &real.Retrievers{
		"Mozilla/5.0",
		time.Minute,
	}
	inspect(r)

	//type assertion
	realRetriever := r.(*real.Retrievers)
	fmt.Println(realRetriever.TimeOut)
}

func inspect(r Retriever) {
	fmt.Printf("%T %v\n", r, r) //%T表示类型,%v表示结构体的值
	//type switch
	switch v := r.(type) {
	case mock.Retrievers:
		fmt.Println("Contents: ", v.Contents)
	case *real.Retrievers:
		fmt.Println("UserAgent: ", v.UserAgent)
	}
}
/*
mock.Retrievers {this is a fake Retriever}
Contents:  this is a fake Retriever
this is a fake Retriever
*real.Retrievers &{Mozilla/5.0 1m0s}
UserAgent:  Mozilla/5.0
1m0s
*/

接口的组合

只要实现了Retriever和Poster接口的所有函数,就相当于实现了这个接口。
使用者可以实现几个接口。

//接口的组合
type RetrieverPoster interface {
	Retriever
	Poster
}

func session(s RetrieverPoster) string {
	s.Post("http://www.imooc.com", map[string]string{"contents": "This is another fake imooc.com"})
	return s.Get("http://www.imooc.com")
}

//Retrievers即实现了Retriever接口也实现了Poster接口
type Retrievers struct {
	Contents string
}

func (r *Retrievers) Post(url string, form map[string]string) string {
	r.Contents = form["contents"]
	return "ok"
}

func (r *Retrievers) Get(url string) string {
	return r.Contents
}

常用的系统接口

//stringer接口 格式化我们的结构
type Retrievers struct {
	Contents string
}
func (r *Retrievers) String() string {
	return fmt.Sprintf("Retriever: {Contents: %s}", r.Contents)
}

fmt.Printf("%T %v\n", r, r)
//*mock.Retrievers Retriever: {Contents: this is a fake Retriever}

Reader和Writer接口。

func printFile(filename string) {
	file, err := os.Open(filename)
	if err != nil {
		panic(err)
	}

	printFileContents(file)
}
//只要实现了Reader接口的类型,都可以使用这个方法,不一定是文件,如下面代码中的字符串
func printFileContents(reader io.Reader) {
	scanner := bufio.NewScanner(reader)

	for scanner.Scan() {
		fmt.Println(scanner.Text())
	}
}

func main() {
	//fmt.Println(convertToBin(13))
	printFile("abc.txt")

	s := `abc"a"
	das
	张晋嘉
	`
	printFileContents(strings.NewReader(s))
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值