設計模式有何不妥,所謂的荼毒體現在哪?

在@庄表偉老師的回答 什麼是 Agile Methodology(敏捷軟體開發)?里看到這麼一句話「設計模式的流毒真的不少」。不知設計模式的荼毒體現在何處?


一句話

To A Man with a Hammer, Everything Looks Like a Nail.

舉個明白點的例子,轉個之前看到的東西

讓我們專註於這個例子。這個問題很經典:寫一個在標準輸出列印「你好世界!」的程序(在 Java 中):

System.out.println("hello world");

代碼看起來太簡單了。讓我們能不能用用幾個設計模式?

看看……

首先我們定義兩個介面對象和監聽器來增加監聽器。

public interface Subject {
public void attach(Observer observer);
public void detach(Observer observer);
public void notifyObservers();
}
public interface Observer {
public void update(Subject subject);
}

再定義 HelloWorldSubject 和 HelloWorldObserver 然後實現它們。

private ArrayList& observers;
private String str;
public HelloWorldSubject() {
super();
observers = new ArrayList&();
}
public void attach(Observer observer) {
observers.add(observer);
}
public void detach(Observer observer) {
observers.remove(observer);
}
public void notifyObservers() {
Iterator& iter = observers.iterator();
while (iter.hasNext()) {
Observer observer = iter.next();
observer.update(this);
}
}
public String getStr() {
return str;
}
public void setStr(String str) {
this.str = str;
notifyObservers();
}
}
public class HelloWorldObserver implements Observer {
public void update(Subject subject) {
HelloWorldSubject sub = (HelloWorldSubject)subject;
System.out.println(sub.getStr());
}
}

然後我們增加一個命令。

public interface Command {
void execute();
}
public class HelloWorldCommand implements Command {
private HelloWorldSubject subject;
public HelloWorldCommand(Subject subject) {
super();
this.subject = (HelloWorldSubject)subject;
}
public void execute() {
subject.setStr("hello world");
}
}

然後我們增加一個抽象工廠。

public interface AbstractFactory {
public Subject createSubject();
public Observer createObserver();
public Command createCommand(Subject subject);
}
public class HelloWorldFactory implements AbstractFactory {
public Subject createSubject() {
return new HelloWorldSubject();
}
public Observer createObserver() {
return new HelloWorldObserver();
}
public Command createCommand(Subject subject) {
return new HelloWorldCommand(subject);
}
}

然後最後地,一個單件。

public class FactoryMakerSingleton {
private static FactoryMakerSingleton instance = null;
private AbstractFactory factory;
private FactoryMakerSingleton() {
factory = new HelloWorldFactory();
}
public static synchronized FactoryMakerSingleton getInstance() {
if (instance == null) {
instance = new FactoryMakerSingleton();
}
return instance;
}
public AbstractFactory getFactory() {
return factory;
}
}

最後是主類。

public class AbuseDesignPatterns {
public static void main(String[] args) {
AbstractFactory factory = FactoryMakerSingleton.getInstance().getFactory();
Subject subject = factory.createSubject();
subject.attach(factory.createObserver());
Command command = factory.createCommand(subject);
command.execute();
}
}

然後輸出:

Hello World

哇,我們在 Hello World 中用了四個設計模式耶!(好吧,其實還有一個迭代器,但我們使用了 Java 的內建迭代器)這一定是一個優秀的設計! 但存在什麼問題?

對 Hello World 程序,它太複雜。

它包含了我們不可能需要的靈活性。

設計和實現它是徹底的對時間的浪費。

它違反了 KISS 原則。[3]

它沒有圍繞問題的目標製作。原來的初衷是學習在標準輸出上列印而這些代碼已經離他們太遠。

總結:自然地使用設計模式,不要濫用用他們。設計模式對設計卓越軟體很有用。明智而不濫用地使用他們。

原文在這裡 譯言網 | 在「你好,世界!」程序中濫用的設計模式


「設計模式就是在你用的(垃圾)語言里無法轉化成庫的抽象」by Edward Kmett


設計模式本身沒有問題,問題是人們使用的方式。

理想的情況下應該是:代碼重構到設計模式

模式和重構之間存在著天然聯繫,模式是你想到達的目的地,而重構則是從其他地方到達這個目的地的條條道路——Martin Fowler《重構》

過度設計和設計模式是兩個很有意思的詞語,這取決於我們是不是預先式設計。通過以往的經驗我們很容易看到一個環境來識別一個模式。遺憾的是使用設計模式依賴於我們整個團隊的水平。對於了解設計模式的人來說,設計模式就是一種溝通語言。而對於了解一些設計模式的人來說,設計模式就是複雜的代碼。

並且在軟體迭代的過程中需求總是不斷變化的,這就意味著我們對代碼設計的越早,在後期失敗的概率也就越大。設計會伴隨著需求而發生變化,在當時看起來合理的設計,在後期就會因此而花費過多的代價。

而如果我們不進行一些設計,就有可能出現設計不足。這種情況可能出現於沒有時間寫出更好的代碼的項目,在這些項目里由於一些原因出現加班等等的原因,使得我們沒有辦法寫出更好的代碼。同時,也有可能是因為參考項目的程序員在設計方面出現不足。


設計模式需要有大量的編程經驗,才可以讓我們實現:重構到設計模式。


好吧,專註黑設計模式十餘年的我來湊個熱鬧。

設計模式而言,其本身沒有任何問題。

所有的設計模式,都是廣泛運用於OO軟體開發中的常見的一些Pattern(個人認為應當翻譯成手法,而非模式)。

這些Pattern我都用了好多年了,並且也將一直用下去。

真正流毒甚廣的,就是GoF的這本書《設計模式》,或者說中文版流毒最甚

設計模式這本書的英文全稱是:Design Patterns - Element of Resuable Object-Oriented software design

從英文原文來說,問題不大,因為大概意思是:一些設計手法的集錦,進行可復用的面向對象軟體設計的基礎


中文版翻譯成計模式:可復用面向對象軟體的基礎。一下子就高大上了有木有?甚至於很多人根本都不知道這個小標題,只知道:《設計模式》,卧槽,又是設計又是模式的。這一定是葵花寶典一樣的不傳之秘,不學會這個,你好意思說你會做軟體設計?


結果就是一幫子像我這樣的把設計模式用了幾年的人,因為沒聽說過神馬裝飾模式,神馬享元模式,一下子就low爆了好不

設計模式你妹啊!

就是一大堆有幾年經驗的程序員都知道的手法集錦而已啊,說白了就是寫給第一次去西餐廳吃牛排的二貨的一本入門手冊而已

軟體開發中的Pattern何止20餘種,成百上千好不?像PHP裡面的$conn || $conn = mysql_connect( $server );這也是一種Pattern啊,反覆出現啊。


《設計模式》的流毒在於,一本講Element的書被抬高到了銀彈的程度,沒有銀彈啊你們這群low逼二貨老闆,回去把《沒有銀彈》再反覆讀十遍。

《設計模式》的流毒還在於,他給low逼們一條快速提升逼格的途徑,那就是把所有設計模式的名字都!背!下!來!

君不見多少二貨整天樂此不疲的背誦設計模式的名字,而連一行像樣的代碼都寫不出來。

順便說一下,還有很多人說,設計模式建立了一套話語體系,讓我們這些有逼格的程序員可以用一個名詞來指代一個三兩句話說不清的Pattern,提高了溝通的效率。

不得不說我曾經被這種說法唬住過,

但事實的真相是,程序員其實是這樣溝通的:

這個類負責創建這個對象,對。然後這邊包裝一下,對的。
嗯,你這個類就是針對他的Interface做的一個Adapter,是的。
你這個只創建一次,提高性能。對。

和那些高大上的名詞有個屁的關係。兩個程序員在一個層次的時候,根本不需要任何裝逼的名詞都能很順暢的溝通

最後送所有程序員兩句話:

通向二逼之路,常由逼格鋪就。
沒有銀彈。


共勉之。


說道這個設計模式. GOF 23. 我最近在不斷面試中深有體會. 我發現一個毛病.很多工程師都拿這個GOF說事,貌似簡歷上如果少了這個Title,就會立即減分不少. 後面在隨便談談其中一些模式解決的問題和使用的場景時卻支支吾吾,完全說不清. 後來隨著這種情況出現次數也逐漸.我突然感到GOF就像一個遮羞布一樣,或對他們來說只是一個裝飾品.

其實我一直很反感那些比較資深工程師對剛入門新人提出一些所謂的」指導「. 類似這個GOF.說道這可能有人吐槽我了. 「我把自己的經驗無償教授給你 你還不樂意" 其實並非不樂意,這些經驗的形成都是有其獨特個人背景因素在裡面,而這些個人因素是沒法複製的, 如果經驗傳授,我們渴望方向是能獲得提升,如果實際的情況因為這些所謂「經驗」對我們基本判斷照成衝擊或形成顧慮,那就得不償失了。經驗上指導是否成功判斷點在於這個經驗是否真的卓有成效,而不是說你不願不願意教授.?

工程師個人精力是有限的,學習東西更應該具有批判性, 況且先不論GOF有多大用處, GOF說到底是來解決問題的,如果因為使用GOF而帶來更多額外困惑成本要高於問題本身,那我們為何要用它呢?其實GOF本身並沒有錯,而是使用的人除了問題. 有些人從來不糾結GOf到底解決了什麼問題,其實與其記住每個GOF實現細節【況且大部分人記不住】還不如記住其使用場景作用大得多, GOF不是銀彈,在某些問題上確實是劈柴. 那些滴信GOF自身的人可以看出是受了太多所謂的牛人經驗之談的影響,而失去自己的最基本的判斷選擇能力. 可見獨立思考的能力有多重要.


嘛我們老師有句話,叫做methodology就是not having a theory。只有那種自己搞不清楚的語言才會在那要求別人需要遵循什麼methodology【對java說的就是你


設計模式說白了就是在不允許使用dynamic_cast的情況下如何讓你的設計通過類型系統的檢驗,於是發明出了一大堆行之有效的做法。為什麼不能用dynamic_cast?因為通常如果你可以通過修改設計來避免所有dynamic_cast,那你就得到了最優的性能(通常指的是係數,不是複雜度)。

但是很多人都知其然不知其所以然,盲目的背誦卻不練習(這並不是讓你不要去背誦),喜歡過度設計控制不住自己,還可以拿它來裝逼等等。其實這都不是設計模式的問題,而是人的劣根性的問題,這些人不管學什麼都是一樣的,只不過設計模式把這些人的效果放大了。


直白地說,

為了模式而模式
就像為了OOP而OOP
為了UML而UML
為了文檔而文檔
為了TDD而TDD
為了DSL而DSL
為了BEST PRACTICE而BEST PRACTICE
為了SCRUM而SCRUM
為了招聘而招聘
為了管理而管理
為了戰爭而戰爭
為了搞對象而搞對象
為了生孩子而生孩子...

人類的潛台詞是:因為我「能」

荼毒就是,這些東西「銀彈」般的營銷,給人類的因「能」而做,不負責任提供了溫床。


設計模式本來是工程中普遍的優雅的實現方式的一個集合,目的是為了讓後人少走彎路,從本質上講這只是一種建議。而從業者們(或者學院老師)都愛將設計模式奉為瑰寶,任何時候都嘗試用設計模式去鞭策自己的實現,「這是不是某個模式?是,牛逼。不是,能不能套用某個模式?」,所以這就限制思維。在自由和禁錮面前,我想牛逼的人都願意選擇自由吧。

而 Java 則是一門典型「設計模式過度」的語言,設計模式隨處可見。這與 Java 這門語言本身有關,就像這門語言天生就是為設計模式準備的。作為一門工廠語言,Java 的設計者在設計這門語言的時候,就嘗試用各種設計模式將這門語言牢牢「規範化」。簡單,讓這門語言門檻降低;採用設計模式規範化,讓使用者可以耍的花樣就少,於是犯錯的機會就少。這也就是 Java 為企業所青睞的原因,也是 Java 能夠支撐起這麼多大型項目的原因。

至於設計模式本身,用,但不濫用。


喬峰拿少林長拳也能打死武林高手,然而用少林長拳並且到處嚷嚷欺行霸市的都是只會長拳的末流地痞流氓。


流毒在於平庸的人看不到技術內涵,只拿技術,新名詞裝逼。

流毒在於這些人寫的東西,你不得不去維護。


多看看金庸有助於理解這個問題:

超一流高手,無招勝有招;
一流高手,招式爐火純青;
二三流,欺負一般人。

一看勤奮二看悟性。另外,唯快不破也算適用吧。


設計模式的鼓吹者的說法通常是這樣的:

  • 你項目不夠大, 項目大了設計模式就有用了
  • 你還沒到用設計模式的高度, 不是你想學就能學的
  • 設計模式沒問題, 是你有問題

這根本就不是科學, 是宗教


--- 補充一點點 ---

有用的東西都會被做成框架和庫, 沒用的東西卻不會. 如果你抽象水平有限, 看見模式卻不知道怎麼寫成函數, 那麼你至少得學習一些反模式避免踩坑. 一些靜態代碼分析工具, 例如 facebook/infer 也可以給你指出不少底層代碼的反模式. 但... 架構反模式怎麼學習? 我只能說你可以從 Martin Fowler 的博客中學習到一些.


毒性不小,容易讓人誤以為學會區區這幾個設計模式,就相當於學會設計了。


舉個例子,我們組這半年使用Node, Gulp, Angular積攢了一些經驗,前兩天隔壁組有人來找我們開個技術交流會,他們在做一款內部工具,基於Web,瀏覽器運行。主要負責的哥們是個Java Developer,一小時的會,有五十分鐘都在給我們展示他的project(主要由jQuery, RequireJS構成),一個簡單的Toolbar和裡面幾個button,把jQuery的輪子全部重新造了一遍,主要業務邏輯還沒影呢,輪子的unit test已經達到了98%的覆蓋率,Code Review時言必談design pattern。

然而他的JS裡面所有的class都用 var ClassName = (function ( ) {return {props..., func...} }( ) ),貌似父類和子類的繼承關係,也是通過jQuery.extend(parentLiteralObject, childLiteralObject)。我們提出為什麼不用prototype實現class時,哥們說他們是用到了"JavaScript Reveal Pattern"。我連續幾遍強調不管什麼pattern,你的method都不在prototype上面,而是在各自的instance上面。

最後我發現,哥們其實並不了解什麼是prototype,怎樣在JS中實現class和繼承,以及前端開發中什麼交給庫來做,什麼是真正的業務邏輯,並且採用Java applet 和 Swing等面向過程的方式來進行web前端開發。甚至於在函數中做參數檢測時還不看具體情況的統一使用if (param != null) 這種模糊的邏輯判定。

不敢說荼毒,但事倍功半是肯定的。


設計模式當然不光是指GoF,也不是OO/命令式語言專用的

所謂設計模式就是代碼形狀(Code Shape)的設計模式,這包括所謂的「編程範式」在內的,因為編程範式也是對代碼形狀的設計。按照這個思路來理解,函數式編程、邏輯式編程當然也是設計模式的一種。設計模式不僅不會不妥,而是沒有人可以不使用設計模式


不妥的是還沒有達到一定層次時,你的簡歷不得不寫上它.


那個用貂蟬激怒呂布殺董卓的辦法
叫什麼來著?
我們這次對付友商。。。
老大,那叫美人計。。。
。。。對!就叫美人計!

設計模式和三十六計差不多
設計模式是一種溝通語言
本身沒什麼缺點
但過度設計會因此產生,吃飽了撐著的總喜歡畫蛇添足


設計模式就是寫字本上的格子。
像我女兒這水平,寫字離開了格子就歪歪扭扭,忽大忽小。
像我,白紙上寫得幾個碑帖正楷,倒也能橫豎對齊,上下得體。
更有大家,拿去方格紙去求字,必被轟出來。
是白是黑,各自對號入座。若是我女兒不肯用方格本,必屁股上留下五指印。


設計模式本身沒問題;有問題的是會點設計模式就覺得自己高人一等的偽高手。


推薦閱讀:

TAG:軟體開發 | 編程 | 設計模式 |