Go语言是彻底的面向组合的并发语言

面向组合编程从AOP的Mixin,然后到Ruby的Traits,直至DCI设计,包括Scala的trait的组合设计,这些都有一个共同特点,组合特性是显式的,也就是说要用专门语法来声明组合。其实组合设计应该是面向对象设计中很自然的一种方式,也就是说,只要你使用面向对象语言,隐式上你就具备了强大的组合能力,而无需另外用trait这些语法专门实现。 来自Less is Exponentially More认为: If C++ and Java are about type hierarchies and the taxonomy of types, Go is about composition. 如果说C++和Java是关于类型的层次和分类,那么Go是关于组合。 组合 我们看看Go语言申明一个具有属性字段和方法的类型竟然采取完全平等的方式定义,然后将它们组合成一起,假设一个对象Door有一个属性标识当前状态,两个方法打开和关闭,GO代码如下: type Door struct { opened bool } func (d *Door) Open() { d.opened = true } func (d *Door) Close() { d.opened = false } 这三大行代码分别是定义一个struct(静态结构)和两个动态功能方法Open()和Close()。Go中是没有Java的Class类的概念,因此,我们不能将静态结构和动态行为混合在一个类中,其实一般情况下,将两者分离是有好处的,因为结构一般是不变的,具有不可变性,而需要混合的情况基本是需要状态可变的,这时使用Go的CSP模型(类似Actor模型)即可。Go语言的这种动静分离设计非常巧妙。 Go语言倡导使用组合替代继承,那么组合能否实现多态性呢?继承中多态性是通过多个子类继承父类来实现,组合是如何实现?下面看看Go语言的组合多态性的实现: package main import ( "log" ) type B struct{ } func (b B) foo() { log.Printf("...") } type A struct { B } func main() { var a A a.foo() } 以上代码点按http://play.golang.org/p/IU7xq62WC-直接运行。 foo()是B的方法 但是B嵌入了A中,那么其方法可以看成A的方法被直接调用。这虽然很像Java中A extends B,也就是A继承了B。Go语言通过组合实现了Java传统语言中使用继承实现的多态性。 如果上述被嵌入A中的B是一个接口怎么办呢?在Java中如果一个字段是接口,我们需要通过依赖注入或IOC容器将接口的实现子类注入进去,这是我们使用组合方式经常碰到的场景,当然我们一直期待Java能够将依赖注入加入语言机制,从Java9的提前披露设计中我们丝毫看不到这种倾向,不知道那些参与Java规范设计的人是否经常使用Java开发企业应用,基于JVM的Scala的依赖注入也是如此。 假设B是一个接口: package main import ( "log" ) type B interface { foo() } type A struct { B } func (a A) foo() { log.Printf("...") } func main() { var a A a.foo() } http://play.golang.org/p/p3wATT9I2F 我们为A实现接口B的foo()方法,是不是类似将func (a A) foo()注入到了type A struct中,当然因为这里B是接口,不能使用a.B.foo()调用,而前面一个例子B是一个实体,可以使用a.B.foo() 因为Go语言自然的语言组合能力,我们不必借助额外依赖注入框架实现组合+注入了,这大概是我初期最为惊讶的。同时,那些所谓Mixin或trait功能都自然地融合在这种组件实现中了,比如A本来没有方法foo(),Go语言本身将B的foo()编织weaving进入了A。 并发 回到文章开始举例Door,Door是一个有状态的对象,但是守护改变其状态的行为却被拆解在外面,通过组合对接进去,我个人认为这其实是一种贫血模型或者失血模型,类似Java的只有setter/getter方法的POJO,而我们在DDD设计中,倡导使用富模型聚合根来实现,通过聚合根守卫状态,而且聚合根之间通过消息事件驱动,Go的CSP模型可以帮助我们实现。 Go 的CSP模型是使用channel 和goroutine 开发并行程序的能力,协程是一种绿色线程,不是真正的操作系统的线程,而是使用操作系统的一个线程进行不断切换使用,类似Node.JS的单线程异步并发原理,这种花销很小的并发能力比多线程并发要更经济。你不能在JVM上实现Actor, 绿色线程和CSP CSP如下代码: package main import "fmt" import "time" func sleepAndTalk(secs time.Duration, msg string, c chan string) { time.Sleep(secs * time.Second) c <- msg } func main() { c := make(chan string) go sleepAndTalk(0, "Hello", c) go sleepAndTalk(1, "Gophers!", c) go sleepAndTalk(2, "What's", c) go sleepAndTalk(3, "up?", c) for i := 0; i < 4; i++ { fmt.Printf("%v ", <-c) } } http://play.golang.org/p/vIH6o-o-HB c := make(chan string)是生成一个通道,go标识协程,同时执行。协程与channel的关系类似于Java中线程与队列。多个CSP作为聚合根能够串联起来:

原文发布于微信公众号 - Golang语言社区(Golangweb)

原文发表时间:2016-12-09

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏java架构师

设计模式学习笔记之组合模式模式

我们常常会遇到一类具有“容器”特征的对象,他们既是容器,本身也是对象。比如,公司人员管理中的人,他们是处于不同层级,每个层的人下边,又有下属。也就是数的结构。 ...

2966
来自专栏java达人

把好方法参数的大门

做编程工作这几年来,见识了不少烂代码,最常见的就是像下面那样的: public void execute(Args args){ //方法体内对args没有作...

1997
来自专栏数据小魔方

Python可视化笔记之folium交互地图

leftlet给R语言提供了很好用的交互式动态地图接口,其在Python中得API接口包名为folium(不知道包作者为何这样起名字,和leaflet已经扯不上...

4844
来自专栏喔家ArchiSelf

全栈Python 编程必备

Python作为一种编程语言,被称为“胶水语言”,更被拥趸们誉为“最美丽”的编程语言,从云端到客户端,再到物联网终端,无所不在,同时还是人工智能优选的编程语言。

3575
来自专栏机器学习算法与Python学习

Python再次更新! 解锁与优化多项新特性......

Python 3.7.0 版本于 6 月 27 号正式发布,该版本有多项重大的更新和改进,主要内容如下如下:

1070
来自专栏黑泽君的专栏

java多线程、集合和IO面试题_02

1131
来自专栏大数据挖掘DT机器学习

Python]新手写爬虫全过程(已完成)

今天早上起来,第一件事情就是理一理今天该做的事情,瞬间get到任务,写一个只用python字符串内建函数的爬虫,定义为v1.0,开发中的版本号定义为v0.x。数...

3879
来自专栏猿人谷

对缓存的思考【续】——编写高速缓存友好代码

开篇 上一篇博文对缓存的思考——提高命中率详细介绍了高速缓存的组织结构,并通过实例说详细明了cpu从高速缓存中取数据的过程,对于缓存的工作机制应该有了清晰的认识...

24910
来自专栏猿湿Xoong

一个bit一个bit的进行 Base64 白话科普,看不懂算你输

1114
来自专栏有趣的django

python开发面试问题

python语法以及其他基础部分 可变与不可变类型;  浅拷贝与深拷贝的实现方式、区别;deepcopy如果你来设计,如何实现;  __new__() 与 __...

4628

扫码关注云+社区

领取腾讯云代金券