Go语言中的面向对象

我们用钻头,目的不是为了钻他两下,而是为了想要一个窟窿眼。

面向对象也一样,用OOP只是手段,写出好维护的代码才是目的。

不是为了面向对象而强行面向对象,是通过吸收面向对象的精华,写更优秀的代码。

1.面向对象拆解

面向对象能流行,因为确实很优秀。

  • 可复用,不用子类多写代码,父类方法就能给子类方法复用。
  • 灵活扩展,尽管父类已经定义了主体逻辑,但子类可以自由选择怎么实现。
  • 好维护,符合开闭原则,对添加子类开放,对修改父类关闭。对子类的改动不用担心影响全局(不可能一点都不改吧)。

那go语言跟普通面向对象语言差异这么大,是怎样仍然完美拥有这些优点呢。

1.1映射

如果把 Java 类拆解到go里,属性就是struct,方法就是interface。但构造方法不在其列。

比如java类可以这样写

class Bird{
    private String name;
    public String getName(){ return this.name; }
    public void fly(){}
}

go 里可以这样写

type IBird interface{
    fly()
}
type Bird struct{
    IBird
}
func (b *Bird)fly(){}
// 构造函数 返回值类型是interface
func NewBird() IBird{
    return &Bird{}
}

go 语言里,返回值类型是重点。返回值类型不是定义的struct,而是interface。

那么能不能不返回定义的 interface,而是返回定义的 struct呢?

答案是不行。这就涉及到两种语言对代码复用的实现方式。

1.2继承和组合

在java这类面向对象的语言上,复用是通过继承的方式来实现的。

子类继承父类,子类完全可以代替父类来使用。

class A{
    public void show(){}
}
class B extends A{}

public void letShow(data A){
    data.show();
}

letShow(new B());

上述操作是完全没问题的,因为 B 也是 A的一种。

但是在go里,上述就行不通了。

go的复用是通过组合的方式来实现的。没有父类子类的概念,而是超集的概念。

超集可以执行子集的方法,但是不支持作为子集类型被传入。

type Base struct{}
func (b Base) Show() {}

type Super struct {
    Base
}

func callBase(b Base) {}

super := Super{}
// 可以执行子集的方法
super.Show()
// 但不支持作为子集类型被传入
// Cannot use 'Super{}' (type Super) as type Base 
// callBase(Super{})

所以你来我往大家操作的类型都是 interface。

1.3殊途同归

但回过头仔细想想,一般情况下,Java里所有的属性都建议设为private,不对外开放。外部只能调用方法来处理。跟go里也差不多。

这种机制在java里只是写起来有些死板,但是在go里,直接就被定死了,想要灵活,想要复用就只能返回 interface。

这样一想,写java的时候念头都通达了。OOP的时候不用再想着和谁干点什么,而是想着找个能干的就行,管他是谁呢。

2.面向对象实战

众所周知,百闻不如一见,百看不如一干。所以我们以一个线上需求实践一下。

需求:将多个数据源提供的数据入库,各个数据源提交来的字段不一样,但最终落地的数据字段是一致的。

2.1 代码

下面的代码不是很规范,用了几个魔数,类型还用了map。忽略细节,看本质。

真正写代码不会有人这样写的。

真正写代码不会有人这样写的。

真正写代码不会有人这样写的。

dddd

无封装写法

func saveData(request map[string]string) {
    dataToSave := ""
    switch request["version"] {
    case "source1":
        dataToSave = extractFromSource1(request)
    case "source2":
        dataToSave = extractFromSource2(request)
    }
    if dataToSave != "" {
        Save(dataToSave)
    }
}

简单封装写法

type IExtract interface {
    Extract(request map[string]string) *model.data
}
type AbstractExtractor struct{
    IExtract
}
type Extractor1 struct {
    AbstractExtractor
}
type Extractor2 struct {
    AbstractExtractor
}

func GetExtractor(request map[string]string) IExtract {
    switch(request["version"]) {
    case "source1":
        return &Extractor1{}
    case "source2":
        return &Extractor2{}
    }
    return nil
}

func saveData(request map[string]string) {
    extractor := GetExtractor(request)
    if extractor == nil{
        return
    }
    Save(extractor.Extract(request))
}

其实还可以封装得再给力一点,比如

  • 分到不同的文件,改动一个逻辑的时候尽量不影响其他逻辑。
  • 干掉那个Switch,让他自己动(反射、map或者init)。

后面有机会再说。

2.2分析

封装了,代码反倒更长了。

所谓一寸长,一寸强,有谁会拒绝更长的呢。

复用性:只要在 AbstractExtractor 名下定义的方法, Extractor1 和 Extractor2都能调用。

灵活扩展:如果要增加一种数据源,可以采用近似于新加子类的方式操作

好维护:假如 Extractor2 和 Extractor1 某个地方不一样,自己改自己的就行了,不用担心影响全局。

上面不就是一个典型的工厂模式吗

2.3拓展

那么好好的面向对象怎么不能用了,就算用了经典的面向对象,现有的特性应该也可以完全保留。

好端端的,为什么非要用这种方式拆开呢?

业务还没写好,就不想这种终极问题了。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,921评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,635评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,393评论 0 338
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,836评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,833评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,685评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,043评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,694评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 42,671评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,670评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,779评论 1 332
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,424评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,027评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,984评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,214评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,108评论 2 351
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,517评论 2 343

推荐阅读更多精彩内容