zoukankan      html  css  js  c++  java
  • 批判《不懂接口、反射、委托、设计模式足足写了5年的代码》(技术篇)

      原文地址:不懂接口、反射、委托、设计模式足足写了5年的代码 -- 写给初学者(谈美女生成器不谈代码生成器)

      吉日有三篇文章,是我最深恶痛绝的,堪称误导新人之三部曲

    1.白话讲反射技术 --- 适合初学者入门引导

    2.白话讲山寨SOA,少一些迷惑、多一些理解,你的程序架构SOA了吗?

    3.不懂接口、反射、委托、设计模式足足写了5年的代码 -- 写给初学者(谈美女生成器不谈代码生成器)

      相信大家都拜读过了,不管是抱着娱乐的心态,抑或是想从中学习的热情。

    第1篇是有严重错误的,属于不懂装懂型的水文。相关错误参见小赵的这篇文章:谈吉日嘎拉的《白话反射技术》及其他(技术篇)

    第2篇则是根本就没用过SOA,脑子一热却跳出来教育新人。相关批判参见:我眼中的SOA,以及在实际项目中的应用经验

    第3篇则是最空洞无物的一篇。打着“不懂……却写了5年代码”作幌子,“教育”初学者,却没有任何实际内容。这也是我本文要批判的主题。

      批判《不懂接口》一文,真的很难,因为文中也就那个图和下面的4点原则和他要说的主题有关系。至于其他文字,都是废话,不看也罢。

      对于那个图,也就是所谓的“美女生成器”,姑且不论它的粗俗,但我想,也正是这一点,博得了下面一群看客的叫好声,然而当我们仔细看图,以及图中的6段文字,会发现它毫无教育意义。

      首先这是一个流程图,而不是UML图。在没有UML图的配合下,是很难看懂例子中接口、继承、组合关系的。所以说,做技术的严谨,在此人身上毫无体现。

      那好吧,让我们将就着看下去。

          image 

      为什么输入参数也可以是接口,而不光是变量和类呢?

      这牵扯到了方法设计的原则,而与接口设计原则无关。

      在大量的设计实践中,我们发现,在声明方法的参数类型时,要尽可能地指定最弱的类型,并且在基类上定义接口,这样才可以输入更广泛的参数类型,灵活性就更大。

      吉日的文字是含糊的,他只是把一个小经验拿出来,但是知其然不知其所以然,更不要说能解释给初学者听了。

          image

      这个地方说的是inline函数,就是根据石头和水,先做出黄金,再做出来钻石,最后生成美女,也就是最终的返回值。说到底还是把一个复杂的方法拆分成3个简单的方法,按照吉日的思路,代码应该是下述这样的: 

        public class MMConverter
        
    {
            
    public MM ConvertFromStoneToMM(IStone stone, Water water)
            
    {
                var gold 
    = ConvertFromStoneToGold(stone, water);

                var diamond 
    = ConvertFromGoldToDiamond(gold);

                
    return ConvertFromDiamondToMM(diamond);
            }


            Gold ConvertFromStoneToGold(IStone stone, Water water)
            
    {
                
    return new Gold();
            }


            IDiamond ConvertFromGoldToDiamond(Gold gold)
            
    {
                IDiamond diamond 
    = DiamondFactory.CreateDiamond("Shanghai");

                Console.WriteLine(diamond.Quality);

                
    return diamond;
            }


            MM ConvertFromDiamondToMM(IDiamond diamond)
            
    {
                
    return new MM();
            }

        }

      明眼人应该看出来了,这种拆分是面向过程的做法,和接口设计扯不上关系。

          image

      数这段注释问题最多,分别讨论如下:

      1)“系统有明确的输出”。由于系统的输入参数的类型范围要尽可能的宽,所以吉日在反向思考后,认为系统的输出(也就是返回类型)要尽可能的窄,尽量不要限于一个具体的类型。而且,在吉日的10年编码生涯中,经过重复重复再重复的代码机式编程,也感觉到返回类型似乎应该是明确的。

      但是,他只说对了一半。我们要谅解他10年来的大半时间在进行过程式编程,在没有polymorphism(包括override和overload)的情况下,吉日自然是觉得需要什么就返回什么了。

      我们举一个例子,写一个IO操作的方法,到底是返回FileStream还是返回Stream呢?我必须诚实地讲,没有定论。除非我事先知道肯定是文件的IO操作,这时候肯定直接返回FileStream;否则,请大家返回到Stream级别的对象。

      我在想,如果方法仅返回类型不同,也算是一种overload,那么就不会没有定论了。有几个类型我就写几个overload方法,这是最霸道的做法。但可惜的是,只有IL允许这么搞,C#做不到。

      2)“不可能这里输出的是油,应该输出钻石就输出钻石?这句话就比较扯淡了,我是没读明白。那些挺“吉”的fans,谁能帮我解释解释?

      3)此外我对“当然还可以有多个输出,例如ref、out等”这句话感到莫名其妙。我们知道,ref和out是基于语言的,解决的是向方法传递的是参数的一份copy还是参数引用本身这样的问题,而和接口以及OO设计没有关系。

      这里就属于吉日穷显摆了,我们真的需要使用ref和out在工厂方法中返回多个输出么?没必要,或者说这是一种糟糕的设计,无疑给初学者极大的误导。

      在OO的设计中,如果真的需要有多个输出,我们可以把这个变量提升到类的级别,这样就可以在方法返回前,设置这个变量的值,以达到同样的功效。或者,对于多个输出,可以把它们抽象为一个实体的两个属性,让方法返回这个实体类型就可以了。

      而对于ref和out,我曾经做过两年的VB6,对此深有体会,在面向过程的编程模型中,ref的使用是非常频繁的。

      这么看,吉日写了10年程序,虽然也在用C#,不客气地说,还是基于面向过程的编程方式,他所谓的重构,只是把一段代码抽象为一个方法。在抽象的过程中,由于原先面向过程的编程模型,而他又把握不好如何按照OO的思想重构,就只好大量的使用ref来拆东墙补西墙了。

          image

      这段注释是最费解的,因为按照他的流程图,我找不出“接口对不上”这句话中“接口”所指,更提不上“中间处理转换一下”。

      根据我的经验,做出如下2种猜测:

      1)有一些程序员没有养成良好的术语习惯,不区分“接口”和“接口方法”,所以他们常说“我到时候暴露一个接口给你调用”,而对方一般也能听懂。

      2)如果吉日真的是在处理接口兼容性的问题,那么他这里提到的“中间处理转换一下”,无外乎以下几种模式:AdapterProxyFacadeBridge。Adapter和Proxy是最容易想到的,因为它们能处理大部分的接口兼容性问题。但是,吉日还停留在过程式编程的阶段(虽然他不一定承认),我想,他这里应该指的是Facade吧。我又去翻了他另外的水文,就是那些只有图片和广告而没有思想和实现的《通用权限》和《大恶人闭门造车》系列文章,从数据库操作的封装上,大致证实了我的猜测。

      我在上述模式下面都添加了超链接,指向我早期写的设计模式系列文章,对设计模式不是很熟悉的朋友可以点击了解相关技术。

          image 

      让我们来看第5点,

      画了一堆图,就这个比较靠谱,说得是简单工厂,应该大书特书一笔的,结果是一句话“这就是所谓的接口,就这么简单”,轻描淡写敷衍了事。

      我一时手痒,给出了它的实现:   

    Code

          image

      我说这段全都是废话,那些挺“吉”的人心里肯定不爽。说了半天,还是把几千行的方法拆成若干小方法的事情,用不着你说,那些新人照样知道要这么写程序。

      我们再来看他总结的所谓4条原则,水分就更大了,4条原则都是套大帽子,都没有错,但也啥都没说清楚,所以说是水文,让我们一条条分析:

    1。分工、职责明确原则:每个装置都有明确的分工,都应明确的功能定位,该干啥的,就应该干啥,职责定位不能乱套,你不能指望汽车飞起来,飞机潜入海底吧,该干啥的就应该干啥?一个函数不要写太长,也有这个味道,应该干啥的都区分好,别写个上千上万行的代码出来。

    评:老生常谈,把几千行的方法拆成若干小方法的事情又说一遍。

    2。输入、输出明确原则:每个装置都有明确的输入输出,甚至都有阀值限制、严格输入输出的参数,应该流进来什么?进行什么样的处理,最后流出去什么?往小了讲,类似我们天天写的一个函数、往大了讲,就是类似我们公司开发的一个个子系统,每个函数,每个子系统都应该有明确的功能定位,不应该重复、不应杂乱无章。

    评:方法的参数和返回值的范围:参数类型要尽可能宽,这一点前面我已经给出说明了。但是返回类型不一定是窄的。吉日认为需要严格控制输出,太狭隘了,那是面向过程的做法,在OO的世界里,输出类型可宽可窄,我在上面图中的第3点注释中已经解释过为什么了。

    3。接口、规范原则:流入的口径、螺纹、材质,流出的口径、螺纹、材质等,都应该是有些行业规范的,否则一个装置架构完毕后,要流到下一个装置去处理,那不是流不下去了?或者可以中间用特殊的管道,把这2个设备都连接上,这个管道的2头,跟这些设备都有标准可以接,就像有些电脑的转接头一样,例如usb转啥啥的等等。

    评:这是在说啥?前面说行业规范,为什么流不下去了?后面谈到的管道和USB,在设计模式中其实都是一个Adapter。哦,我明白了,吉日是想告诉我们前面作出一个A类型的对象,但是后面需要一个B类型的对象。

    真的流不下去了么?如果A是从B中派生的,也流不过去么?当然可以流过去。而真正需要Adapter的,指的是A不从B中派生的情况。

    4。可替换、可升级可更新原则:一个庞大的化工厂,往往会进行一些维修、升级某个装置或者某个设备的情况,你总不能要求整个化工厂全体都升级,那不是开玩笑的,好像建立一个上规模的化工厂要几百亿,这钱都是用火车拉,也能拉几节车厢的,不是想更新了就更新了,想不要了,就不要了。
        例如,我们车子的一个螺丝坏了,我可以选择A公司生产的相同型号的螺丝,也可以采用B公司生产的相同型号的螺丝,这就是因为这些螺丝,都能有相同的功能,都能满足规定的要求规范。

    评:这里的可替换、可升级、可更新原则,说得就是组件的热插拔了。给新人讲这个是不负责任的,因为这里牵扯到要面向接口编程,所有的零件都要做成工厂,我们所要写的每个类都应该是:接口.方法();,而不是:具体类.方法();。试问吉日,你写过面向接口的程序么?你能分辨出什么时候用接口,什么时候用抽象类么?你做过组件的设计期行为么?

    当然,我也时刻在反思,设计模式和接口委托这些技术的粒度究竟有多大?难道一定要用化工厂维修设备的这么复杂的场景来描述么?大炮打蚊子,还是杀鸡用牛刀?

      终于写完了,我的感受是,2个字:痛苦。读吉日的文章,错别字和病句抛开不说,经常是看着看着就跑题了,到了该深入讲解的时候,又含糊其辞,没有任何设计思想,UML图解和代码实现就更不要说了,流程图画的很炫却起不到实际意义,主观意识太重,以至于很多地方经不起推敲。

      《不懂接口》一文中,吉日观点总结如下:

    1.输入输出,前者宽,后者窄(其实后者是没有定论的)

    2.需要工厂为我们生成对象(工厂这个词是我说的,原文没有)

    3.需要把一个几千行代码的方法拆分成职能单一的小方法(这个用不着你说,就像说煤球是黑的一样)

    4.需要提供一个自动选择生成不同对象的机制(什么机制呢?没说)

    5.需要USB这样的管道(怎么实现呢?没说)

      吉日此文的题目是《不懂接口、反射、委托、设计模式足足写了5年的代码 -- 写给初学者(谈美女生成器不谈代码生成器)》,但我还是那句话,初学者能从中学到啥呢?你随便找本书看看都比浪费时间看他的东西强。

      吉日是一个写了10多年程序的程序员,但是,基本停留在面向过程的基础上,听这样一个人讲接口、委托、工厂和OO,那就是一个笑话。而且他口无遮拦还真敢讲,更是滑天下之大稽。这是我花了一晚上时间,分析完他这篇文章后,对他的进一步认识。

      最后,奉劝初学者,如果你们真想看明白接口、委托之类的技术,还是买一本《你必须知道的.NET》吧,你也可以选择《CLR via C#》。这些都是语言和设计思想中最重要的概念,千万不要被吉日的这几篇水文给毁了。

      本文实例代码完整下载:program.zip

  • 相关阅读:
    centos7.6 安装与配置 MongoDB yum方式
    MongoDB 介绍
    centos 关闭selinux
    前端 HTML标签属性
    前端 HTML 标签嵌套规则
    前端 HTML 标签分类
    前端 HTML body标签相关内容 常用标签 表单标签 form里面的 input标签介绍
    前端 HTML body标签相关内容 常用标签 表单标签 form 表单控件分类
    前端 HTML form表单标签 select标签 option 下拉框
    POJ 1426
  • 原文地址:https://www.cnblogs.com/Jax/p/1585697.html
Copyright © 2011-2022 走看看