那才是不利的入门编制程序的架势,正确的编制

最近两个星期,我使用 plantuml (贝尔实验室出品了一个超级绘图工具 graphviz, 这是一个包装版)把我的绘图项目做了一次全面的接口和类的可视化。使用了很多设计模式,包括:桥接、装饰器、生成器、抽象工厂。绘制完后,图像是很美的,接口之间的交互和参数定义清晰优雅。很漂亮!

前言:

看到很多零基础但很想学习编程的小伙伴经常会遇到这么个问题——入门阶段太难了,往往理解一个概念就需要花费很多时间和精力,而这个过程是特别容易产生挫败感进而质疑自己太笨啦、不适合学编程啦这些心理。

还有的虽然知道了这个概念是什么意思,但在实际中碰到类似的问题时却不知道怎么去运用这个概念。
这里谈谈我以前入门阶段是怎么自学以及如何应对上面的问题的。因为水平有限,有些方面不一定是正确的,所以需要小伙伴们去实际验证一下,然后欢迎指出我不正确的地方,谢谢!

然并卵!

入门Python时的常见问题(用的是<笨方法学Python>这本书):

这个项目在开发之处已经违反了我的一些感觉,对于程序设计的感觉。从我对数据库和服务器的多年经验,使用基于数据表和数据解释的抽象结构,你总能获得最简单易用可扩展的软件结构。

对一些编程概念的理解:

我是先看书上的解释,然后再看例子,同时跟着书上的例子去写代码,这个过程我是大概知道这个概念的意思,但为了能彻底吃透,我会用搜索引擎去查有没有更好的讲解,这里我会限定收集的条目数,个人认为不宜过多,多了容易混乱,然后也是不断去根据讲解写代码加深理解,最后,我会让自己用隐喻的方式来解释这个概念。

不过,这个绘图项目真的很复杂,涉及了很多的多态和关联。比如,在一个长的列表中存储种类不同的图形,这些图形存储的绘图数据和相关信息都不同,我需要把这些数据视做同一种类型,然后迭代它们,选出需要的一个并且使用它的相关信息。所以,我尝试使用学术界的设计模式来解决其中的问题。

举个例子:

Python中的变量:变量是用来指代某个东西的名字。
这里我就会跟着书上的示例代码去做,a = 'string' b = 1 然后就是print这个变量,然后在结果输出前先根据概念的解释去想出应该输出什么结果,然后再和程序的输出相比。如果到了这里还不是很理解,那我就会多写几次代码(不是照着书上的)做不同的尝试:一般到了这个步骤已经能很好的理解这个概念了,最后为了校验,我就用自己的话去解释这个概念:变量就像银行卡,往卡里存了几百万后,在消费时用这张卡结算,就相当于变量指代某个变量值的原理。

当项目变得很庞大的时候,我意识到设计模式屁都不是。诸如桥接、装饰器以及其他,都是建立在一种假设,假设你的父组件和子组件总是可以忽略对方的细节,而可以统一的处理它们。比如,面包有奶油味、抹茶味、水果味,面包又有低档材料、高档材料,那么你可以把味道和材料分为两个不同的接口,然后各自抽象,并且组合这两个接口生成更丰富的面包,比如低档材料的抹茶味面包。但是,真实的编程世界中,这样的理想状态非常少。在真实的编程世界中,面包还想要更多的东西,比如奶油味的有糖,抹茶味的没有糖,有糖的面包放在左边柜台上,没有糖的面包放在右边柜台上。看到了吧,复杂度升级了,柜台跟面包有没有糖是绑定的。这意味着,如果你想像前面那样抽象两个接口---味道和材料,那你现在必须考虑柜台。因为低档材料的抹茶味面包是没有糖的,放在右边柜台。现在,你不得不抽象出味道和柜台的关系。在上面的接口之上再增加一层。每当你的需求复杂一点,这种层就会升级。比如,红糖面包和白糖面包。

总之,就算设计模式避免了类继承的爆炸,但是也避免不了抽象层级的复杂。

所以,我觉得我又不会编程了。于是,我尽可能的重新思考这些设计,并且重新在网络上搜寻曾经支持我的设计论调:面向数据结构编程而不是对象。如果不是为了这个绘图项目,我绝对不会冒险再一次使用设计模式和面向对象。

我当然搜到了一大堆 Linus 排斥面向对象和 C++ Java 的话语,从感觉上,这些就是我面临设计困难时候的感觉。我曾经无数次这样解决我的程序设计。

git的设计其实非常的简单,它的数据结构很稳定,并且有丰富的文档描述。事实上,我非常的赞同应该围绕我们的数据结构来设计代码,而不是依据其它的,我认为这也是git之所以成功的原因之一。[...] 依我的观点,好程序员和烂程序员之间的差别就在于他们认为是代码更重要还是数据结构更重要。

在庞大的项目中,人们对不是自己开发的模块并不了解,能快速理解其他模块中函数的确切含义才能提高开发效率。而C++引入的各种抽象则使代码非常依赖上下文,想理解一段代码,需要看多得多的上下文。

面向对象语言以对象为核心,加一些相关联的方法,简直是呓语。重要的东西应该是数据结构,对象本身有啥重要?真正有意思的,是在不同类型的不同对象交互而且有锁规则的时候。但是,即使是这时候,封装什么“对象接口”也绝对错误,因为不再是单一对象的问题了。

有趣的是,这里有一篇另外一位前辈的很早的文字,推在 Google+ 上,来自 Unix 核心创建者之一 Rob Pike:

原文链接
A few years ago I saw this page: http://www.csis.pace.edu/~bergin/patterns/ppoop.html

Local discussion focused on figuring out whether this was a joke or not. For a while, we felt it had to be even though we knew it wasn't. Today I'm willing to admit the authors believe what is written there. They are sincere.

But... I'd call myself a hacker, at least in their terminology, yet my solution isn't there. Just search a small table! No objects required. Trivial design, easy to extend, and cleaner than anything they present. Their "hacker solution" is clumsy and verbose. Everything else on this page seems either crazy or willfully obtuse. The lesson drawn at the end feels like misguided epistemology, not technological insight.

It has become clear that OO zealots are afraid of data. They prefer statements or constructors to initialized tables. They won't write table-driven tests. Why is this? What mindset makes a multilevel type hierarchy with layered abstractions better than searching a three-line table? I once heard someone say he felt his job was to remove all while loops from everyone's code, replacing them with object stuff. Wat?

But there's good news. The era of hierarchy-driven, keyword-heavy, colored-ribbons-in-your-textook orthodoxy seems past its peak. More people are talking about composition being a better design principle than inheritance. And there are even some willing to point at the naked emperor; see http://prog21.dadgum.com/156.html for example. There are others. Or perhaps it's just that the old guard is reasserting itself.

Object-oriented programming, whose essence is nothing more than programming using data with associated behaviors, is a powerful idea. It truly is. But it's not always the best idea. And it is not well served by the epistemology heaped upon it.

Sometimes data is just data and functions are just functions.

--- Rob Pike (One of the Unix creators (Ken Thompson, Dennis M. Ritche, and Rob Pike))

几年前我看到了这个网页: http://www.csis.pace.edu/~bergin/patterns/ppoop.html

我真的不知道这篇文章到底是不是在搞笑。读了一下,我虽然很想说这不是一篇搞笑的文章,但是,拜托,它根本就是。让我来跟你们讲讲他们在搞笑什么吧。

e...按照他们的话语,我应该称自己为 hacker (黑客),不管我不关心这些。Hello! 你只需要一个小的不能再小的 table ! 根本不需要什么对象。朴素平凡,容易扩展,容易清除,(比起他们的那种设计)多 TM 简单。他们的 “hacker solution” 真的是又蠢又笨。他们写出来的那堆东西到处透漏着疯狂和愚蠢。他们缺乏技术认知。

很显然,OO 的狂热者们害怕数据。他们喜欢用语句或者构造器来初始化 tables 。他们根本不写 table-driven 的测试。Why is this? 得有多大的心才会选择用多级并且多层的类抽象,而不去用一个小小的三行 table ? 我曾经听说有人用各种 OO 的东西替换掉 while 循环。

不过好消息是,hierarchy-driven, keyword-heavy, colored-ribbons-in-your-textook orthodoxy 这些东东快到头了。更多的人选择组合而不是继承。有些人已经重新开始认识 OO。

面向对象编程语言,其本意是使用数据和相关的行为进行编程,这是一个很好的想法。事实确实如此。但是,这个想法并不总是最好的 idea。 这个想法并没有完全的认知编程的世界。

Sometimes data is just data and functions are just functions.

--- Rob Pike (Unix 创建者之一的 (Ken Thompson, Dennis M. Ritche, and Rob Pike))

没错,我们需要的就是数据的抽象和数据的解释器。用表来存储你需要的各个数据,对于多态,C 语言中简单直接干净:union。使用这么一个简单的结构,你能存储各种不同的类型,而且你只需要存储他们的指针,这意味着你不会浪费多少内存,同时你能获得相同内存段但是数据不同的抽象。

然后,使用一个链表或者数组,把这个 union 装进去,遍历,cast,然后使用你需要的特定数据。

很多语言都有 union 的变体,现代语言中的泛型就是 union 的一种语法糖,但是你往往忘记了这种结构的真正价值和用意。仔细体会下这个全新的设计:

enum ShapeKind {
  skLINE, skPORT, skBOARD
}

class Shape {
  kind: ShapeKind   
  value: Line | Port | Board
  contains(x: number, y: number): boolean
}

class ShapeContainer {
  shapes: Array<Shape>
  search(x: number, y: number): [ShapeKind, Shape]
}

type
  ShapeKind = enum
    skLINE, skPORT, skBOARD

  Shape = ref object
    case kind: ShapeKind
    of skLINE:
      line: Line
    of skPORT:
      port: Port
    of skBOARD:
      board: Board
    contains: (x: number, y: number): bool

  ShapeContainer = object
    shapes: seq[Shape]

proc search(c: ShapeContainer, x: number, y: number): tuple[kind: ShapeKind, shape: Shape]

本文由明仕msyz手机版发布于家居装修-蜗牛装饰,转载请注明出处:那才是不利的入门编制程序的架势,正确的编制

TAG标签:
Ctrl+D 将本页面保存为书签,全面了解最新资讯,方便快捷。