那般清楚面向对象编程,正确的编程姿势

git的筹划其实尤其的归纳,它的数据结构很平稳,并且有抬高的文档描述。事实上,作者非凡的同情应该围绕大家的数据结构来统筹代码,而不是基于其它的,我觉着那也是git之所以成功的来头之一。[…]
依小编的意见,好程序员和烂程序员之间的歧异就在于他们认为是代码更关键依然数据结构更关键。

在偌大的类型中,人们对不是友好开销的模块并不打听,能高效明白其余模块中函数的适用含义才能增强支付作用。而C++引入的各个抽象则使代码卓殊重视上下文,想清楚一段代码,须求看多得多的上下文。

面向对象语言以目的为主干,加一些相关联的方法,简直是呓语。首要的事物应该是数据结构,对象自我有甚首要?真正有意思的,是在不相同档次的例外目的交互而且有锁规则的时候。不过,即便是此时,封装什么“对象接口”也相对大错特错,因为不再是纯粹对象的标题了。

天真的面向对象编程

PrintOS.java

 

1 public class PrintOS
2 {
3     public static void main(final String[] args)
4     {
5         System.out.println(OSDiscriminator.getBoxSpecifier().getStatement()) ;
6     }
7 }

OSDiscriminator.java

 

 

01 public class OSDiscriminator // Factory Pattern
02 {
03     private static BoxSpecifier theBoxSpecifier = null ;
04     public static BoxSpecifier getBoxSpecifier()
05     {
06         if (theBoxSpecifier == null)
07         {
08             String osName = System.getProperty("os.name") ;
09             if (osName.equals("SunOS") || osName.equals("Linux"))
10             {
11                 theBoxSpecifier = new UNIXBox() ;
12             }
13             else if (osName.equals("Windows NT") || osName.equals("Windows 95"))
14             {
15                 theBoxSpecifier = new WindowsBox() ;
16             }
17             else
18             {
19                 theBoxSpecifier = new DefaultBox () ;
20             }
21         }
22         return theBoxSpecifier ;
23     }
24 }

BoxSpecifier.java

 

 

1 public interface BoxSpecifier
2 {
3     String getStatement() ;
4 }

DefaultBox.java

 

 

1 public class DefaultBox implements BoxSpecifier
2 {
3     public String getStatement()
4     {
5         return "This is not a box." ;
6     }
7 }

UNIXBox.java

 

 

1 public class UNIXBox implements BoxSpecifier
2 {
3     public String getStatement()
4     {
5         return "This is a UNIX box and therefore good." ;
6     }
7 }

WindowsBox.java

 

 

1 public class WindowsBox implements BoxSpecifier
2 {
3     public String getStatement()
4     {
5         return "This is a Windows box and therefore bad." ;
6     }
7 }

他俩认为上边那段代码没有取消if语句,他们说那叫代码的“logic
bottleneck”(逻辑瓶颈),因为借使您要扩展贰个操作系统的判断的话,你不光要加个类,还要改那段if-else的言辞。

由此,他们整出二个叫Sophisticated的面向对象的缓解方案。

很多语言都有 union 的变体,现代语言中的泛型就是 union
的一种语法糖,可是你频仍忘记了那种结构的的确价值和企图。仔细回味下那么些全新的宏图:

先看那篇教程是怎么来叙述OOP的。它先给了上边那些标题,这一个标题亟待输出一段有关操作系统的文字:若是Unix很科学,Windows很差。

下一场,使用一个链表恐怕数组,把那几个 union
装进去,遍历,cast,然后采取你需求的特定数据。

14         else

原文链接
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.

— 罗布 派克 (Unix 创造者之一的 (Ken 汤普森, Dennis M. Ritche, and
罗布 Pike))

本条把下部那段代码描述成是Hacker
Solution
。(那帮人觉着上面那叫黑客?小编推断这帮人当成没看过C语言的代码)

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]

下一场开端用面向对象的编程形式一步一步地进步这几个代码。

故而,小编以为自家又不会编程了。于是,小编竭尽的重新考虑那一个规划,并且重新在互联网上搜寻曾经帮衬自个儿的宏图论调:面向数据结构编程而不是目的。假使不是为着那一个绘图项目,小编相对不会铤而走险再三遍采取设计形式和面向对象。

11         {

我本来搜到了一大堆 Linus 排斥面向对象和 C++ Java
的言语,从感觉上,那个就是自己面临设计困难时候的感到。作者已经无数十次那样解决本人的次序设计。

进度化的方案

01 public class PrintOS
02 {
03     private static String unixBox()
04     {
05         return "This is a UNIX box and therefore good." ;
06     }
07     private static String windowsBox()
08     {
09         return "This is a Windows box and therefore bad." ;
10     }
11     private static String defaultBox()
12     {
13         return "This is not a box." ;
14     }
15     private static String getTheString(final String osName)
16     {
17         if (osName.equals("SunOS") || osName.equals("Linux"))
18         {
19             return unixBox() ;
20         }
21         else if (osName.equals("Windows NT") ||osName.equals("Windows 95"))
22         {
23             return windowsBox() ;
24         }
25         else
26         {
27             return defaultBox() ;
28         }
29     }
30     public static void main(final String[] args)
31     {
32         System.out.println(getTheString(System.getProperty("os.name"))) ;
33     }
34 }

接下来是多少个童真的面向对象的笔触。

 

 

那个连串在支付之处已经违背了本人的有的感觉,对于程序设计的觉得。从作者对数据库和服务器的多年经历,使用基于数据表和数据表达的架空结构,你总能拿到最简便易行易用可扩充的软件结构。

从罗布 Pike 的 谷歌+上的二个推看到了一篇叫《Understanding Object
Oriented
Programming
》的小说,我先把那篇作品简述一下,然后再说说老牌黑客Rob派克的评介。

总而言之,即使设计情势防止了类继承的爆炸,然则也避免不了抽象层级的错综复杂。

18     }

但是,那个绘图项目实在很复杂,涉及了众多的多态和涉及。比如,在壹个长的列表中蕴藏序列不一的图纸,那个图片存储的绘图数据和有关新闻都不比,小编索要把那几个数据视做同一连串型,然后迭代它们,选出必要的二个并且动用它的相干消息。所以,作者尝试采纳学术界的设计情势来缓解其中的题材。

OO大师的方案

只顾其中的Design Pattern

PrintOS.java

 

 

1 public class PrintOS
2 {
3     public static void main(final String[] args)
4     {
5         System.out.println(OSDiscriminator.getBoxSpecifier().getStatement()) ;
6     }
7 }

OSDiscriminator.java

 

 

01 public class OSDiscriminator // Factory Pattern
02 {
03     private static java.util.HashMap storage = new java.util.HashMap() ;
04   
05     public static BoxSpecifier getBoxSpecifier()
06     {
07         BoxSpecifier value = (BoxSpecifier)storage.get(System.getProperty("os.name")) ;
08         if (value == null)
09             return DefaultBox.value ;
10         return value ;
11     }
12     public static void register(final String key, final BoxSpecifier value)
13     {
14         storage.put(key, value) ; // Should guard against null keys, actually.
15     }
16     static
17     {
18         WindowsBox.register() ;
19         UNIXBox.register() ;
20         MacBox.register() ;
21     }
22 }

BoxSpecifier.java

 

 

1 public interface BoxSpecifier
2 {
3     String getStatement() ;
4 }

DefaultBox.java

 

 

1 public class DefaultBox implements BoxSpecifier // Singleton Pattern
2 {
3     public static final DefaultBox value = new DefaultBox () ;
4     private DefaultBox() { }
5     public String getStatement()
6     {
7         return "This is not a box." ;
8     }
9 }

UNIXBox.java

 

 

01 public class UNIXBox implements BoxSpecifier // Singleton Pattern
02 {
03     public static final UNIXBox value = new UNIXBox() ;
04     private UNIXBox() { }
05     public  String getStatement()
06     {
07         return "This is a UNIX box and therefore good." ;
08     }
09     public static final void register()
10     {
11         OSDiscriminator.register("SunOS", value) ;
12         OSDiscriminator.register("Linux", value) ;
13     }
14 }

WindowsBox.java

 

 

01 public class WindowsBox implements BoxSpecifier  // Singleton Pattern
02 {
03     public  static final WindowsBox value = new WindowsBox() ;
04     private WindowsBox() { }
05     public String getStatement()
06     {
07         return "This is a Windows box and therefore bad." ;
08     }
09     public static final void register()
10     {
11         OSDiscriminator.register("Windows NT", value) ;
12         OSDiscriminator.register("Windows 95", value) ;
13     }
14 }

MacBox.java

 

 

01 public class MacBox implements BoxSpecifier // Singleton Pattern
02 {
03     public static final MacBox value = new MacBox() ;
04     private MacBox() { }
05     public  String getStatement()
06     {
07         return "This is a Macintosh box and therefore far superior." ;
08     }
09     public static final void register()
10     {
11         OSDiscriminator.register("Mac OS", value) ;
12     }
13 }

笔者还十一分的意地说,他加了三个“Mac
OS”的事物。老实说,当自家看来最终那段OO大师搞出来的代码,作者快要吐了。作者瞬间想到了两件事:二个是先前酷壳上的《面向对象是个骗局》和
各个流行的编程格局》中说的“设计格局驱动编程”,另多少个作者想开了那三个被连忙洗过脑的程序员和咨询师,也是那种德行。

于是乎本人去看了眨眼间间第壹我Joseph
Bergin的主页
,这几个Ph.D是果然刚刚完毕了一本关中国“氢弹之父”捷和格局的书。

当项目变得很庞大的时候,作者发觉到设计形式屁都不是。诸如桥接、装饰器以及其余,都以手无寸铁在一种假若,尽管你的父组件和子组件总是可以忽略对方的底细,而得以统一的拍卖它们。比如,面包有奶油味、抹茶味、水果味,面包又有起码材质、高档材料,那么你可以把味道和素材分为多少个例外的接口,然后分别抽象,并且结合那四个接口生成更丰硕的面包,比如低档质感的抹茶味面包。可是,真实的编程世界中,那样的可以状态十一分少。在真实的编程世界中,面包还想要越多的东西,比如奶油味的有糖,抹茶味的尚未糖,有糖的面包放在左边柜台上,没有糖的面包放在左边柜台上。看到了呢,复杂度升级了,柜台跟面包有没有糖是绑定的。那象征,如若您想像前边那么抽象七个接口—味道和资料,这你以往必须考虑柜台。因为低档材料的抹茶味面包是向来不糖的,放在左侧柜台。以后,你不得不抽象出味道和柜台的涉及。在上头的接口之上再追加一层。每当你的须要复杂一点,那种层就会提升。比如,红糖面包和白糖面包。

19 }

然并卵!

15         {

是的,我们必要的就是数量的架空和数目的解释器。用表来存储你需求的各类数据,对于多态,C
语言中简易直接干净:union。使用那样三个简便的结构,你能积存种种差距的品种,而且你只需求仓储他们的指针,那象征你不会浪费多少内存,同时你能获取一致内存段可是多少分化的虚幻。

 

不久前七个星期,我动用 plantuml (Bell实验室出品了1个至上绘图工具
graphviz,
那是三个包装版)把自个儿的绘图项目做了几遍周详的接口和类的可视化。使用了过多设计格局,包含:桥接、装饰器、生成器、抽象工厂。绘制完后,图像是很美的,接口之间的交互和参数定义清晰优雅。很赏心悦目!

 

有意思的是,那里有一篇别的一个人长辈的很早的文字,推在 谷歌(Google)+ 上,来自 Unix
大旨成立者之一 罗布 Pike:

06         if (osName.equals("SunOS") || osName.equals("Linux"))

率先以进度化的思绪来重构之。

Rob Pike的评论

(Rob 派克是那儿在贝尔lab里和Ken一起搞Unix的主儿,后来和Ken开发了UTF-8,未来还和Ken一起搞Go语言。注:不要觉得Ken和Dennis是基友,其实她们才是确实的老基友!)

Rob
Pike在他的Google+的这贴里评论到那篇小说——

他并不确认那篇小说是否搞笑?可是他认为这一个个写那篇文章是很认真的。他说她要评论那篇作品是因为她俩是一名哈克er,至少这么些词出现在那篇作品的术语中。

他说,那么些顺序根本就不要求如何Object,只要求一张小小配置表格,里面配备了对应的操作系统和你想出口的文书。那不就完了。这么不难的设
计,相当不难地扩张,他们格外所谓的哈克Solution完全就是高血压脑出血的代码。前面这一个所谓的代码进化出色疯狂和愚笨的,那几个完全误导了对编程的认知。

然后,他还说,她以为这一个OO的狂热份子卓殊恐怖数据,他们喜欢用多层的类的涉嫌来形成2个当然只须要摸索三行数据表的劳作。他说他已经听他们讲有人在她的做事种用种种OO的事物来替换While循环。(笔者听他们说中国Thoughtworks那帮搞敏捷的人实在喜欢用Object来替换全数的if-else语句,他们甚至还喜爱把函数的行数限制在10行以内)

他还给了八个链接http://prog21.dadgum.com/156.html,你可以读一读。最终她说,OOP的本质就是——对数据和与之提到的行为开展编程。便即便是那样也不完全对,因为:

Sometimes data is just data and functions are just functions.

09         }
16             System.out.println("This is not a box.") ;

自我的驾驭

自个儿认为,那篇小说的事例举得太差了,差得感觉就像OO的高级黑。面向对象编程重视的是:1)数据和其行事的打包封装,2)程序的接口和促成的解耦。你那怕,举一个多个开关和多少个电器的例证,不然似乎STL中,二个排序算法对多个不等容器的例证,都比这么些事例要好得多得多。老实说,Java
SDK里太多如此的事物了。

自己原先给一些专营商讲一些设计方式的培训课,我屡屡提到,那2三个经典的设计方式和OO半毛钱关系远非,只可是人家用OO来落成罢了。设计格局就多少个准则:1)中意于整合而不是一连,2)保护于接口而不是兑现,3)高内聚,低耦合。你看,那完全就是Unix的设计准则

04     {
02 {
10         else if (osName.equals("Windows NT") || osName.equals("Windows 95"))
17         }
12             System.out.println("This is a Windows box and therefore bad.") ;
07         {
05         String osName = System.getProperty("os.name") ;
01 public class PrintOS
08             System.out.println("This is a UNIX box and therefore good.") ;
13         }
03     public static void main(final String[] args)