如此理解面向对象编程

从Rob Pike 的 Google+上的一个推看到了一篇叫《Understanding Object Oriented Programming》的文章,我先把这篇文章简述一下,而后再说说老牌黑客Rob Pike的评论。html

先看这篇教程是怎么来说述OOP的。它先给了下面这个问题,这个问题须要输出一段关于操做系统的文字:假设Unix很不错,Windows不好。java

这个把下面这段代码描述成是Hacker Solution。(这帮人以为下面这叫黑客?我估计这帮人真是没看过C语言的代码)程序员

1算法

2shell

3编程

4windows

5设计模式

6函数

7oop

8

9

10

11

12

13

14

15

16

17

18

19

public class PrintOS

{

    public static void main(final String[] args)

    {

        String osName = System.getProperty("os.name") ;

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

        {

            System.out.println("This is a UNIX box and therefore good.") ;

        }

        else if (osName.equals("Windows NT") || osName.equals("Windows 95"))

        {

            System.out.println("This is a Windows box and therefore bad.") ;

        }

        else

        {

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

        }

    }

}

而后开始用面向对象的编程方式一步一步地进化这个代码。

先是以过程化的思路来重构之。

 

过程化的方案

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

public class PrintOS

{

    private static String unixBox()

    {

        return "This is a UNIX box and therefore good." ;

    }

    private static String windowsBox()

    {

        return "This is a Windows box and therefore bad." ;

    }

    private static String defaultBox()

    {

        return "This is not a box." ;

    }

    private static String getTheString(final String osName)

    {

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

        {

            return unixBox() ;

        }

        else if (osName.equals("Windows NT") ||osName.equals("Windows 95"))

        {

            return windowsBox() ;

        }

        else

        {

            return defaultBox() ;

        }

    }

    public static void main(final String[] args)

    {

        System.out.println(getTheString(System.getProperty("os.name"))) ;

    }

}

而后是一个幼稚的面向对象的思路。

幼稚的面向对象编程

PRINTOS.JAVA

1

2

3

4

5

6

7

public class PrintOS

{

    public static void main(final String[] args)

    {

        System.out.println(OSDiscriminator.getBoxSpecifier().getStatement()) ;

    }

}

 

OSDISCRIMINATOR.JAVA

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

public class OSDiscriminator // Factory Pattern

{

    private static BoxSpecifier theBoxSpecifier = null ;

    public static BoxSpecifier getBoxSpecifier()

    {

        if (theBoxSpecifier == null)

        {

            String osName = System.getProperty("os.name") ;

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

            {

                theBoxSpecifier = new UNIXBox() ;

            }

            else if (osName.equals("Windows NT") || osName.equals("Windows 95"))

            {

                theBoxSpecifier = new WindowsBox() ;

            }

            else

            {

                theBoxSpecifier = new DefaultBox () ;

            }

        }

        return theBoxSpecifier ;

    }

}

 

BOXSPECIFIER.JAVA

1

2

3

4

public interface BoxSpecifier

{

    String getStatement() ;

}

 

DEFAULTBOX.JAVA

1

2

3

4

5

6

7

public class DefaultBox implements BoxSpecifier

{

    public String getStatement()

    {

        return "This is not a box." ;

    }

}

 

UNIXBOX.JAVA

1

2

3

4

5

6

7

public class UNIXBox implements BoxSpecifier

{

    public String getStatement()

    {

        return "This is a UNIX box and therefore good." ;

    }

}

 

WINDOWSBOX.JAVA

1

2

3

4

5

6

7

public class WindowsBox implements BoxSpecifier

{

    public String getStatement()

    {

        return "This is a Windows box and therefore bad." ;

    }

}

他们以为上面这段代码没有消除if语句,他们说这叫代码的“logic bottleneck”(逻辑瓶颈),由于若是你要增长一个操做系统的判断的话,你不但要加个类,还要改那段if-else的语句。

因此,他们整出一个叫Sophisticated的面向对象的解决方案。

OO大师的方案

注意其中的Design Pattern

PRINTOS.JAVA

1

2

3

4

5

6

7

public class PrintOS

{

    public static void main(final String[] args)

    {

        System.out.println(OSDiscriminator.getBoxSpecifier().getStatement()) ;

    }

}

OSDISCRIMINATOR.JAVA

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

public class OSDiscriminator // Factory Pattern

{

    private static java.util.HashMap storage = new java.util.HashMap() ;

 

    public static BoxSpecifier getBoxSpecifier()

    {

        BoxSpecifier value = (BoxSpecifier)storage.get(System.getProperty("os.name")) ;

        if (value == null)

            return DefaultBox.value ;

        return value ;

    }

    public static void register(final String key, final BoxSpecifier value)

    {

        storage.put(key, value) ; // Should guard against null keys, actually.

    }

    static

    {

        WindowsBox.register() ;

        UNIXBox.register() ;

        MacBox.register() ;

    }

}

BOXSPECIFIER.JAVA

1

2

3

4

public interface BoxSpecifier

{

    String getStatement() ;

}

DEFAULTBOX.JAVA

1

2

3

4

5

6

7

8

9

public class DefaultBox implements BoxSpecifier // Singleton Pattern

{

    public static final DefaultBox value = new DefaultBox () ;

    private DefaultBox() { }

    public String getStatement()

    {

        return "This is not a box." ;

    }

}

 

UNIXBOX.JAVA

1

2

3

4

5

6

7

8

9

10

11

12

13

14

public class UNIXBox implements BoxSpecifier // Singleton Pattern

{

    public static final UNIXBox value = new UNIXBox() ;

    private UNIXBox() { }

    public  String getStatement()

    {

        return "This is a UNIX box and therefore good." ;

    }

    public static final void register()

    {

        OSDiscriminator.register("SunOS", value) ;

        OSDiscriminator.register("Linux", value) ;

    }

}

WINDOWSBOX.JAVA

1

2

3

4

5

6

7

8

9

10

11

12

13

14

public class WindowsBox implements BoxSpecifier  // Singleton Pattern

{

    public  static final WindowsBox value = new WindowsBox() ;

    private WindowsBox() { }

    public String getStatement()

    {

        return "This is a Windows box and therefore bad." ;

    }

    public static final void register()

    {

        OSDiscriminator.register("Windows NT", value) ;

        OSDiscriminator.register("Windows 95", value) ;

    }

}

MACBOX.JAVA

1

2

3

4

5

6

7

8

9

10

11

12

13

public class MacBox implements BoxSpecifier // Singleton Pattern

{

    public static final MacBox value = new MacBox() ;

    private MacBox() { }

    public  String getStatement()

    {

        return "This is a Macintosh box and therefore far superior." ;

    }

    public static final void register()

    {

        OSDiscriminator.register("Mac OS", value) ;

    }

}

做者还很是的意地说,他加了一个“Mac OS”的东西。老实说,当我看到最后这段OO大师搞出来的代码,我快要吐了。我瞬间想到了两件事:一个是之前酷壳上的《面向对象是个骗局》和 《各类流行的编程方式》中说的“设计模式驱动编程”,另外一个我想到了那些被敏捷洗过脑的程序员和咨询师,也是这种德行。

因而我去看了一下第一做者Joseph Bergin的主页,这个Ph.D是果真刚刚完成了一本关于敏捷和模式的书。

Rob Pike的评论

(Rob Pike是当年在Bell lab里和Ken一块儿搞Unix的主儿,后来和Ken开发了UTF-8,如今还和Ken一块儿搞Go语言。注:不要觉得Ken和Dennis是基友,其实他们才是真正的老基友!)

Rob Pike在他的Google+的这贴里评论到这篇文章——

他并不确认这篇文章是否是搞笑?可是他以为这些个写这篇文章是很认真的。他说他要评论这篇文章是由于他们是一名Hacker,至少这个词出如今这篇文章的术语中。

他说,这个程序根本就不须要什么Object,只须要一张小小的配置表格,里面配置了对应的操做系统和你想输出的文本。这不就完了。这么简单的设计,很是容易地扩展,他们那个所谓的Hack Solution彻底就是笨拙的代码。后面那些所谓的代码进化至关疯狂和愚蠢的,这个彻底误导了对编程的认知。

而后,他还说,他以为这些OO的狂热份子很是惧怕数据,他们喜欢用多层的类的关系来完成一个原本只须要检索三行数据表的工做。他说他曾经据说有人在他的工做种用各类OO的东西来替换While循环。(我据说中国Thoughtworks那帮搞敏捷的人的确喜欢用Object来替换全部的if-else语句,他们甚至还喜欢把函数的行数限制在10行之内)

他还给了一个连接http://prog21.dadgum.com/156.html,你能够读一读。最后他说,OOP的本质就是——对数据和与之关联的行为进行编程。便就算是这样也不彻底对,由于:

Sometimes data is just data and functions are just functions.

个人理解

我以为,这篇文章的例子举得太差了,差得感受就像是OO的高级黑。面向对象编程注重的是:1)数据和其行为的打包封装,2)程序的接口和实现的解耦。你那怕,举一个多个开关和多个电器的例子,否则就像STL中,一个排序算法对多个不一样容器的例子,都比这个例子要好得多得多。老实说,Java SDK里太多这样的东西了。

我之前给一些公司讲一些设计模式的培训课,我一再提到,那23个经典的设计模式和OO半毛钱关系没有,只不过人家用OO来实现罢了。设计模式就三个准则:1)中意于组合而不是继承,2)依赖于接口而不是实现,3)高内聚,低耦合。你看,这彻底就是Unix的设计准则

(全文完)

相关文章
相关标签/搜索