如此理解面向对象编程

如此理解面向对象编程

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

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

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

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.") ;
		}
	}
}

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

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

过程化的方案

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"))) ;
	}
}

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

幼稚的面向对象编程

public class PrintOS
{
	public static void main(final String[] args)
  	{
		System.out.println(OSDiscriminator.getBoxSpecifier().getStatement()) ;
 	}
}

 

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 ;
	}
}

 

public interface BoxSpecifier
{
	String getStatement() ;
}

 

public class DefaultBox implements BoxSpecifier
{
	public String getStatement()
	{
		return "This is not a box." ;
  	}
}

 

public class UNIXBox implements BoxSpecifier
{
	public String getStatement()
	{
		return "This is a UNIX box and therefore good." ;
  	}
}

 

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

public class PrintOS
{
  	public static void main(final String[] args)
  	{
		System.out.println(OSDiscriminator.getBoxSpecifier().getStatement()) ;
  	}
}
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() ;
  	}
}
public interface BoxSpecifier
{
  	String getStatement() ;
}
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." ;
	}
}
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) ;
 	}
}
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) ;
	}
}
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的设计准则

(全文完)

(转载本站文章请注明作者和出处 酷 壳 – CoolShell ,请勿用于任何商业用途)

好烂啊有点差凑合看看还不错很精彩 (63 人打了分,平均分: 4.25 )
Loading...

如此理解面向对象编程》的相关评论

  1. 先生你好。
    对于OO大师的方案,Rob Pike的评论。我想说的是:
    要看你的软件目标是什么?如果只是一次性,当然没有必要写那么多类。
    而如果你的软件是通用的,大型的,你就必要要考虑要不要将一个“现在看来是小东西”的变成一个类了。

  2. You will divide a big problem to lots of small problems no matter whatever method you use. So you will often face lots of small problem. For them, instead of using cumbersome OO way lightweight procedural methods are the best choice. But OO fans often take the opposite way. No matter how small a problem is, there is always heaps of codes. Take not a musket to kill a butterfly.

    @伊尔菲斯清晨

  3. apl :
    先生你好。
    对于OO大师的方案,Rob Pike的评论。我想说的是:
    要看你的软件目标是什么?如果只是一次性,当然没有必要写那么多类。
    而如果你的软件是通用的,大型的,你就必要要考虑要不要将一个“现在看来是小东西”的变成一个类了。

    感觉上,这也是个度的问题; 大项目生命周期中,其实需要有人不停的重构代码基,这种变复杂的概率很低,与其它模块耦合性又不大的东东,完全可以等到出现万一情况的时候,重构代码来解决。

  4. 别忘了, Everything is Object ….
    Linux is object, windows is object
    they are all operating system
    so base class will be OS,
    linux, windows should be inherit from OS base class..
    哈哈

  5. 关于OO的书籍也罢,博文也罢,大都拿简单的例子来阐述OO。太简单的例子,体现不出OO的好处,倒是暴漏了缺点:一大堆接口、类。太复杂的例子本身又把读者搅得头晕脑涨,偏离了主题。真是个两难的境地。 简单例子讲OO是让读者理解OO,而不是真教人拿OO解决这些小case。

  6. 其实,每种编程范式。都有他们的应用场景。前面的评论也说了,最根本是为了解耦。
    再深入一些,就是人的大脑没法一下子处理很多东西,需要将他们分解,也就是降低复杂度。一段代码只解决一个问题,一个模块只解决一组相似的问题。

  7. 实际上blog的作者使用了一个多态的方法实现了responder chain,虽然看起来对于这个方案显得有些复杂,但是再经常使用OOP的人严重,或许这比一个switch case或连续if else查表更容易理解。
    另外,他这里使用这种返回字符串的方法来讲述不是一个好的概念,因为返回数据用查表实现确实更简单,但如果getBoxSpecifier是一个有一定功能的方法(比如检查当前系统中有没有安装对应系统的虚拟机,当然,这个例子扯得有点远),那么使用查表+函数指针的方式就不如多态的方法了。

  8. 不过在军工领域,大型软件的开发还是以OO为主流。。。不过没觉得什么不合适的,貌似在这个领域OO确实起到了抽象数据及逻辑的很好的作用。。。当然还有一半以上的东西是用C和汇编。要根据要求来,满足要求是第一位。

  9. sjh :
    不过在军工领域,大型软件的开发还是以OO为主流。。。不过没觉得什么不合适的,貌似在这个领域OO确实起到了抽象数据及逻辑的很好的作用。。。当然还有一半以上的东西是用C和汇编。要根据要求来,满足要求是第一位。

    军工居然还用汇编?

  10. 1. 23个设计模式的确是实用编程技法在oo中的实践,并不只限于oo;因此,23这个数字也只限于像c++、java这样的静态oo语言,在其他语言中,这个数字可能只是10.
    2. 这个例子就是扯淡,弄巧成拙,将问题复杂化了。楼上提到这种oo设计可以应对变化,但是,搞清楚,例子中换了几个实现,但接口都没变,在getDescStringBaseOnOSType这个接口下,明显想到的实现方案就是个查表,而不是什么绕来绕去的oo。
    3. 设计模式的确在解决一些特定问题上很靠谱、很灵活,但他们并不是普适的方案,简单的问题简单解决就够了。
    4. 写这样代码还沾沾自喜的作者应该脸红。

  11. 其实……我这几天一直在想,应该可以证明,面向对象本身是图灵完备的……

    首先,if/switch已经可以用面向对象替代了;然后,既然if能替代,那么就能够通过if控制对象调用链,进而实现循环……然后再定义两个基类:class True和class False,就应该足够像函数式一样自立门户,搞出一套体系了。

    然后,既然面向对象已经图灵完备了,那就让它去和函数式一块玩吧。就别老借用咱老掉牙的过程式编程里面的+、-、*、/、mod等运算符了,直接用面向对象搞一套体系多好,多纯粹……当然咱做工程的,也别乱去搀合。

    等它研究出什么,就好像函数式编程(的lambda之类概念)一样,咱工程界拿过来用就是——其实现在就用了很多了。

    不然这样工程不像工程,科研不像科研,实在不是事……

  12. 如果仔细地看过几个java框架的源码,比如spring,hadoop之类,再来评论,我觉得比较合适
    OO大师在一篇不长的文章里很难举一个真正“实际”的例子,因此种种pattern看上去就变成了杀鸡用牛刀,但那些东西其实在实际环境中是可能有价值的
    这就有个度的问题,在简单明晰和灵活可扩展之间求得平衡,这就是所谓设计的艺术了

  13. #include <stdio.h>
    
    const static char *STATEMENT[] = {
    	"This is not a box.",
    	"This is a UNIX box and therefore good.",
    	"This is a Windows box and therefore bad.",
    };
    
    typedef struct _OSBox{
    	char *osName;
    	int index;
    }OSBox;
    
    const static OSBox OS_TABLE[] = {
    	{"SunOS", 1},
    	{"Linux", 1},
    	{"Windows NT", 2},
    	{"Windows 95", 2},
    };
    
    #define ARRAY_LEN(x) (sizeof(x) / sizeof(x[0]))
    
    int main(int argc, char *argv[])
    {
    	int i;
    	char name[80] = {0};
    	if(argc&lt;2){
    		strncpy(name, "Linux", 80);
    	}else{
    		strncpy(name, argv[1], 80);
    	}
    	
    	for(i=0;i<ARRAY_LEN(OS_TABLE);i++){
    		if(!strcmp(name, OS_TABLE[i].osName)){
    			printf("%s\n", STATEMENT[OS_TABLE[i].index]);
    			break;
    		}
    	}
    	if(i==ARRAY_LEN(OS_TABLE)){
    		printf("%s\n", STATEMENT[0]);
    	}	
    	return 0;
    }

    菜鸟的c语言实现方式,主流的操作系统用手指也数的完,就懒得用哈希表了,for循环足矣:)

  14. marvin :
    我的一句话,面向过程是面向机器,面向对象是面向人的思维。两者没有替代关系

    基本同意你的观点。但这和主题无关。

    函数式据说也是面向人的思维(嗯,数学家应该也算人……吧)

    即便是面向人的思维——请问class human怎么定义?它的继承体系应当如何?

    嗯,随便说说需求:如果我要调查种族歧视问题,那么我要求人按肤色分类;但当我调查宗教问题时,需要人按信仰分类(不要拿肤色来干扰我!);现在,又有个客户要做福利工厂,需要按人的缺陷程度分类(几级伤残、尚可从事何种劳动之类);选拔运动员,需要按体格分类——嗯嗯,诸如选拔体操运动员要重点考察平衡特长之类就不拿出来难为你了……

    当然,你也不能禁止法医来用人这个类库,他更关注人的死法/死因/死相,所以需要按溺死、毒死、锐物刺死……等等分类;此外,先勒死然后丢水里制造溺死假象、先毒死然后焚尸等等又是另外的一些类……

    ——至于医学、人体工学、遗传学乃至虚拟现实(简单者如3D游戏)等等又如何对人分类,就也不拿出来难为你了。

    请问,以上是不是“人的思维”?你能把它“面向对象”出来吗?

    人的确有对事物分“类”的习惯;但“类”的定义,自古就是随心所欲、视所面对的问题而定的。

    合理的分类,自然——显然——能清晰、精确的表达某个领域的当前关注点,甚至推进整个领域的发展。但那是聪明的、智慧的大脑根据实际情况、随机应变作出的睿智抽象。

    即便如此,一个领域的分类,到了另一个领域,那也是“连个笑话都算不上”——得有多蠢,才会把法医学的分类拿到言情剧里去描写“美人”?

    同样的,面向对象很好,但,它真正的好处,是便于实现我们聪明的大脑在面对一个特定问题时,所作出的某种漂亮、简洁、睿智的分类方案而不是其他。

    ——不管是面向过程也好、函数式编程也行、面向对象也罢,归根结底,这些手段的利用者是人、受益对象也是人,对不对?那为何就学不会说人话?

    ——如果哪个蠢货以为生搬硬套个class/inherit,然后把软件搞的像稀屎一样淌来淌去,这就是软件工程师,你不觉得可笑?不想提醒他撒泡尿照照自己的样子?

    ——别怪我说的难听。实在是某些蠢货已经蠢到令人忍无可忍了:我们软件工程师没这么傻,请不要用这种令人哭笑不得的方式黑我们,行不?

  15. 工程学的态度,和科研的态度不同。

    科研是先作出一些基本定义/基本抽象、再搞出一些基本规则,然后探讨在这个规则之下,最终能达到什么程度——他们不关心实用,也不关注性能、可靠性等等指标,他们只关心可行性/可能性。

    比如函数式编程,这个科研人员的大玩具就是这样,被把玩了几十年后,发掘出它的一项可贵潜质:自动化并行。

    即,用它写的程序,可以无需事先声明/设计,就能把一切可以并行执行的东西自动并行执行。而这个特质,刚好又遇到了多核时代,于是一下子就火了起来。

    然后,过程式程序设计的装备库里,就多了个map-reduce。

    面向对象类似。只是它一开始就是过程式程序设计的附属品。
    而它本身,又基本满足了图灵完备性。
    也就是说,面向对象本身,就可以像函数式一样玩——彻底脱离过程式的东西,只用面向对象的语法写一切软件。

    当然,同样和函数式一样,只用函数式语法也能写出一切软件,但过于晦涩艰深,所以函数式语言几乎不会在任何工程中使用。至多如map-reduce一样,借用它的一些不可替代的优良特质。

    正因为不像函数式一样独立,这才导致面向对象狂热者们出现。他们一不懂工程,二玩不透面向对象本身——能玩透,早把面向对象独立出去(因为纯粹的东西才更容易研究其特点和能力),像函数式一样,彻底挖掘出其所可能带来的新思维方式,真正永久改变软件开发格局了——只会卖弄一些很基本、很普通的奇技淫巧:诸如用面向对象代替if之类:可惜,这东西,函数式早玩剩下了,人家连map-reduce都不玩了!

    当然,如果是玩科研,无所谓。玩的弱智就弱智点,无非就是这种半吊子科研项目申请不来经费而已。
    可是,拿它到工程上玩,不好意思,它们难道真以为工程界就这么贱,连这点浅薄的奇技淫巧都看不透、以至于能让这种最初级的科研都看不上眼的败类横行装B?

  16. 假如今生不曾错过你,就不会在这孤独的月下思念,夜太长,思念是一种无言的哀愁,无法抹去。月光浸湿了黑暗,变得透明无比,花语景语皆蒙了一层薄纱,化作寂寞的轻烟。…

  17. apl :
    先生你好。
    对于OO大师的方案,Rob Pike的评论。我想说的是:
    要看你的软件目标是什么?如果只是一次性,当然没有必要写那么多类。
    而如果你的软件是通用的,大型的,你就必要要考虑要不要将一个“现在看来是小东西”的变成一个类了。

    通用的,大型的,还要再故意设计的复杂一些么?
    原始的代码如果新增一种操作系统的判断,是需要修改代码,增加一个else if分支。没错。
    例子中那个复杂的所谓OO设计,需要增加一个类。

    有需求改动,需要修改代码,无可厚非。 问题是, 案例中的好处在哪? 逻辑更清晰了吗? 我看还不如最初的代码一目了然。

  18. ThinkingQuest :

    apl :
    先生你好。
    对于OO大师的方案,Rob Pike的评论。我想说的是:
    要看你的软件目标是什么?如果只是一次性,当然没有必要写那么多类。
    而如果你的软件是通用的,大型的,你就必要要考虑要不要将一个“现在看来是小东西”的变成一个类了。

    通用的,大型的,还要再故意设计的复杂一些么?
    原始的代码如果新增一种操作系统的判断,是需要修改代码,增加一个else if分支。没错。
    例子中那个复杂的所谓OO设计,需要增加一个类。
    有需求改动,需要修改代码,无可厚非。 问题是, 案例中的好处在哪? 逻辑更清晰了吗? 我看还不如最初的代码一目了然。

    @ThinkingQuest
    我的理解是这样的,OO大师的例子中只抽象了一个方法,当抽象出多个方法的时候,面向对象的威力才显现出来,比如说有10个方法,你是在10个地方添加if/else方便,还是扩展一个类方便?

  19. @ThinkingQuest
    如果原始代码不是你写的呢?你还能增加一个else if分支吗?
    如果新增一种操作系统的判断时希望不改动原有代码,甚至能够热部署,显然增加一个else if分支就不行了
    当然,原文例子完全可以用一个简单的配置表实现,问题是例子中的需求太简单(输出一个字符串),如果是更复杂的需求呢?
    用原文的“教学”例子来当批评的靶子显然是有问题的

  20. os_rank.ini

    [os]
    name=linux;windows;os x;free bsd

    [rank]
    linux=This is a UNIX box and therefore good.
    windows=This is a Windows box and therefore bad.

    读之,显示之,想怎么扩展怎么扩展……

    甚至,os_rank.json:
    {“windows”:{“rank”:”3″;”desc”:”This is a Windows box and therefore bad.”;”detail”:{“0”:16; “1”:12;”2″:”40″;”3″:”5″;”4″:”3″;”5″:”0″}}
    }

    读之,显示之,不光可以随意扩展,甚至总评3星、给0星16人、1星12人等等信息都能以[b]同样的模式[/b]显示出来。

    更进一步,引入meta data,不光可以随意扩展操作系统数目,甚至连里面的评价项目、项目数据、项目说明等等,都可以动态增加或者删除,然后以[b]同样的模式[/b]读取并显示出来。

    至于代码,利用json/ini库,读取如上文件并显示,至多50行代码足矣——其中包括详尽的错误提示、包括meta data支持。

    没错,无限扩展的实现,用“过程式”思维只需50行代码。

  21. 另外,既然都是程序员,不妨看看你的source insight或uedit或notepad++之类代码编辑器,看看它们是如何支持“自定义语言”的——当然,你会“惊喜”的发现,它们内置支持的语言,居然是靠同样的一套“表格”驱动的。

    不妨google一下 source insight 支持 php,看看能搜到多少这类东西~~

    不用插件,不必编程,只要配置一个ini(或类似格式的文件),任何代码都能像它们“亲生”的一样得到支持哦亲~~

    ——至于更强悍的vi等等,就不拿出来吓那些外行了……

  22. @invalid
    关键还是看你驾驭抽象的能力了,能把业务模型抽象出来,之后用哪种工具或方法来实现,已经不重要了吧。就看你用哪种工具更熟练了

  23. qingfeng :
    @invalid
    关键还是看你驾驭抽象的能力了,能把业务模型抽象出来,之后用哪种工具或方法来实现,已经不重要了吧。就看你用哪种工具更熟练了

    但是OO大师不关心业务,不关心业务模型,更不关心如何抽象业务模型才能更加简练、精确的解决问题;至于未来的业务扩展能力,更加不会放在他的考虑范围之内——但这些,才是设计的真谛。

    他关心的,就是用OO写if——函数式连map-reduce都研究透了,他觉得用面向对象写if很值的炫耀。

    惊天动地的傻。

  24. 天冷了,屋里的玻璃上有了窗花,各种形状,有的像雪花、像树的枝枝蔓蔓,有的像一匹小马,一只小鹿。这种的冷,在儿时体现的最直接,最形象,记得那时在被窝里躺在炕上,早晨睁着眼,朦朦胧胧的…

  25. @invalid
    你看过原文链接吗?人家哪里在“炫耀”用面向对象写if?不过是篇教学文章罢了,举的例子过分简单了以至于觉得是“大炮打蚊子”而已
    你怎么就得出人家不关心业务,不关心业务模型,不关心如何抽象业务模型才能更加简练、精确的解决问题,不关心未来的业务扩展能力?

  26. @旁观自己

    你看过原文链接吗?人家除了在“炫耀”用面向对象写if还有什么?不过是篇教学文章罢了,举个过分简单了的例子,都能实现成这样……

    穷折腾那么多代码,搞出一跎屎——不好意思,屎先生一般不乱淌的,先道合歉——你怎么就能看出人家关心业务,关心业务模型,关心如何抽象业务模型才能更加简练、精确的解决问题,关心未来的业务扩展能力了呢?尤其是老子贴出50行带meta data的、无限扩展的方案作为对比之后?

    ——————————————————————
    真有能耐,不妨学学函数式,从class True/class False开始,一行过程式代码都别用,从头搞个体系出来。

    否则,就老老实实的,少搞那么多心智垃圾——这东西唯一正确的抽象就是表,进阶抽象是广义表,终极抽象是带meta data的广义表。一样是面向对象。

    还装一脸大师相出来教人呢……不知道面向对象的第一步就是“正确抽象出基础对象/类”吗?就TM个第一步都走不对的白痴,捧臭脚的垃圾还真不少呢。

  27. 看了这篇文章,真是受益了。

    原文作者本身就说,这篇文章来源于:

    The code on this page grew out of a discussion on the Object Technology in Computer Science Education list server.

    作者也说,这个话题很热:

    The discussion had been going on for about 36 hours in late March and early April 2000 centered on the question of “What is OO really; is it a real paradigm, different from procedural programming or is it just a packaging mechanism for procedural programming?”

    原文是”July 30, 2000″更新的。不知为何现在竟被拿出来讨论了。

  28. TAOUP 1.6.9就说过这个问题。有趣的是,那节恰恰引用了Rob Pike的话。看来这种观点也积淀很久了。文中所提的OOP设计那是自寻死路。。

  29. @invalid
    讲话不要这么冲,讨论问题不是吵架骂人
    如果你真正了解过几个java开源项目再评论,我觉得可能更有说服力一点
    现在和你说什么都是白说,你已经陷在偏执的情绪中了,就和博主一样

  30. 记得有这样一篇文章,大意是 “优秀程序员的效率是平庸程序员的十倍” 。

    我得说,这幸亏还是“平庸程序员”。要是和OO大屎比,甩他100倍都别想打住。

    为何会有这么大的差异呢?这篇文章里面的实例就很能说明问题。

    ————————————————————————
    我之前反复讥讽“做这种OO设计,不如把OO独立出来像函数式那样玩”——可惜,那帮战斗力只有5的OO大屎们根本看不懂这句话有多刺眼。

    真知道函数式,就知道我提出的那种所谓的独立OO,其实仍然没有超脱函数式的范畴。但函数式的研究早已突飞猛进,以至于被google发扬光大的map-reduce这种热门技术,在他们那里早已成了“冷门”,没必要花太多精力去研究了。

    也就是说,那帮子还在纠结if的大屎,不过是拿些最最浅薄的东西、最最不重要的东西来唬人罢了。

    ——————————————————————————
    那么,什么重要呢?

    虽然在下也不过是个平庸程序员;但和大屎比,盖他几十倍的底气还是有的。所以,就仍然拿前面提到的那个基于meta data的解决方案做例子吧。

    正如之前一个朋友所说的,只要业务抽象做好,用什么做,无所谓。

    那么,业务抽象如何搞好呢?

    答案就是:吃透各种技术,然后尽量将其用的恰如其分、浑然天成——用大白话说,就是“把技术用到明显该用它的地方”。

    当技术用对了地方时,任何懂甚至只是略懂的人,都会明显觉得,你的设计毫无花巧——因为任何人都会、也应该这么做。

    而只要任何人觉得你把技术用的有点别扭——不好意思,你很可能已经出丑了。

    ——这,大概就是所谓的“代码的坏味道”。

    ——————————————————————————
    和“用对了地方的技术会让人觉得理所当然”一样,从教学的角度看,任何技术,只要放到最能体现它优势的场景去,它就是极易理解的。学会它,不费吹灰之力——哪怕是和过程化思想格格不入的map-reduce,只要理解了面对的问题,学起来都不会遇到任何障碍。

    这样学多了,自然就知道什么是“坏味道”了,也自然就知道如何抽象出精确、高效的业务模型了——然后,10倍于平庸程序员、百倍于OO大屎的效率自然也就出来了。

    反之,如果把技术生硬的用到不适合的地方去,那么自然就难学难懂难理解。甚至就会像这个if……嗯,咱就给OO大屎留点面子吧……

    跟着这种人学多了,做事效率逐渐变得比偶这种平庸程序员还差10倍甚至几十几百倍、甚至完全做不出任何有用的东西,显然都只是个时间问题。

    ——换言之,那个大屎的例子,如果只是个简单的蹩脚方案,并不会激起很大的反映;但它不是的。它教授的,是一个如何把技术用到最不适合的地方去的、最蹩脚的思维方式。任何接受了这种思维方式的家伙,必然在做任何事时,一开始就走向歧途。
    ——而且,更可笑的是,该大屎居然还敢大言不惭的用这种最蹩脚的思维方式去挑战“hacker”这个词:这简直和买辆劳斯莱斯套头驴拉着的暴发户嘲笑舒马赫一样可笑。

  31. @cale @Tian
    好吧,我说的是嵌入式,目前大部分武器设备上的程序,比如导弹的飞控,等等,用的都是汇编+C,或者只用汇编,高级点的飞机的飞控,是VAX+少量汇编+C+少量C++。ada炒作了很长时间,但是一直没有受到太大重视,一个很显然的原因是芯片速度比较慢。。。

  32. 作为面向对象的高级白,我这里有一个还行的改造方案。话说博客大赛没选上十强,很遗憾呢……
    public enum Os
    {
    GNU_LINUX, MAC_OS, WINDOWS_NT, WINDOWS_95, WINDOWS_7, SUN_UNIX
    ;

    static public Os getOs()
    {
    String osName = System.getProperty(“os.name”);
    System.out.println(osName);
    if (osName.equals(“SunOS”)) return SUN_UNIX;
    if (osName.equals(“Linux”)) return GNU_LINUX;
    if (osName.equals(“Windows NT”)) return WINDOWS_NT;
    if (osName.equals(“Windows 95”)) return WINDOWS_95;
    if (osName.equals(“Windows 7”)) return WINDOWS_7;
    return null;
    }
    }

    public class Evaluator
    {
    public String evaluate(Os os)
    {
    switch (os)
    {
    case WINDOWS_NT:
    case WINDOWS_95:
    case WINDOWS_7:
    return “This is a Windows box and therefore bad.”;
    case GNU_LINUX:
    case MAC_OS:
    case SUN_UNIX:
    return “This is a UNIX box and therefore good.”;
    default:
    return “This is not a box.”;
    }
    }

    static public void main(String… arguments)
    {
    System.out.println(new Evaluator().evaluate(Os.getOs()));
    }
    }

  33. 真正面向对象的设计绝不是在显而易见的问题上浪费时间,它是用来描述复杂关系的工具,将各种数据间关系恰当解耦,划分良好的对象边界,将业务逻辑以很清晰的方式描述出来,以便代码具有生命力,能够被安全的修改、增减、删除其中的部分逻辑,以满足现实业务演进的需求,OO是一种方法论,但不是任何人都能真正掌握和恰当运用,就好比文字,不是任何人都能用文字写出优美的文章,但没有文字,肯定没有文章。当系统关系比较复杂,数据门类众多时,如果想正确构建系统,自然而然就会用到OO的方法,就如同建筑,搭个茅棚不需要多少方法,但修建殿堂或者摩天大楼,却是严谨的科学,必须掌握正确的方法(这当然需要天赋,所以也不是任何人,学习点语法,就有能力构建系统的,其实具有构建系统能力的人真的稀缺,绝大部分人只会局部改改代码,加几个if-else分支,根本不懂得适时重构,如果原作者也是勉强把代码堆砌起来,让系统运行的,那这种后继者更将会是一筹莫展,不知从何下手,这就是大坑)。

  34. 用初学编程者教学例子做靶子,确实有点无的放矢,真正的系统哪有这么简单的。OO和ADT、结构化编程,模块化其实是一脉相承的东西,现代的OO语言其实是为这种思想方法在编程实践中的运用提供更好的工具,没有这种思想,当然也用不好这样的工具,反而会因为这种工具超过自己思想能力,责怪工具不好,这就跟很多老人不会使用iphone等智能手机,反而觉得智能手机不如大哥大好用是一回事,我真不知道有那款真正被用户使用的软件是不需要OO方法去构建的,譬如从最早的unix开始,就存在文件的概念,用一个句柄封装真实的IO设备,这不就OO?

  35. @ddou
    很赞成你的观点!其实这个例子也只是表达一种思想,通过简单的例子让我们理解oo的思想,不过有的时候人们会觉得这么简单的东西,不用oo会更方便!

  36. 程序设计方面,完全不可触犯的底线并不多,而“过早优化是万恶之源”就是其中一个。

    优化分性能和架构两个方面。平常人们谈论最多的,是性能方面的过早优化(会如何破坏程序的结构性)。

    而这个大屎的例子,则生动的展示了“过早优化的架构”会带来什么。

    ————————————————————————————
    我之前已经论证过,类并不是基本的。

    类只是随人们关注点不同、甚至关注点相同而关注目的不同、甚至关注点、目的都相同,但处理思路不同而不同的一种伪概念。

    ——————————————————————————
    由于类不是基本的,所以,在设计一个系统时,选择合适的类方案(等价与模块划分方案)就非常重要。

    由于上面这个特点,和那些完全外行的大屎们的妄想不同——类,不可以不假思索的滥用;更不可以在没有明确目的时,先把一切都“class化”再说。

    更不允许,连业务要做什么都没搞清楚,先拉稀一样就把类淌的满地都是。

    这就叫自寻死路。

    ————————————————————————————
    最后,再重复一遍,OO是正确组织代码,以更简练的实现需求(包括扩展方面的需求)的科学,绝不是像大屎那样的跑肚拉稀。

    正如泛文件概念崛起于OO之前,但没人敢说它不是OO一样;跑肚拉稀显然和OO没半点关系;那么,反教人跑肚拉稀的大屎,显然也不是反OO——请勿混淆以上两个概念,更不要用打稻草人的方式为大屎招魂。

回复 陈皓 取消回复

您的电子邮箱地址不会被公开。 必填项已用*标注