日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程资源 > 编程问答 >内容正文

编程问答

论面向组合子程序设计方法 之 南无阿弥陀佛

發(fā)布時(shí)間:2025/3/21 编程问答 20 豆豆
生活随笔 收集整理的這篇文章主要介紹了 论面向组合子程序设计方法 之 南无阿弥陀佛 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.
其實(shí),前面我還忘了提一個(gè)非常重要的基本組合子:singleton。?
這里補(bǔ)充提一下:?
Java代碼??
  • class?SingletonComponent?implements?Component{??
  • ??private?final?Component?c;??
  • ??private?Object?val;??
  • ??public?Class?getType();{??
  • ????return?c.getType();;??
  • ??}??
  • ??public?synchronized?Object?create(Dependency?dep);{??
  • ????if(val!=null);?return?val;??
  • ????val?=?c.create(dep);;??
  • ????return?val;??
  • ??}??
  • ??public?synchronized?Class?verify(Dependency?dep);{??
  • ????if(val!=null);?return?val.getClass();;??
  • ????else?return?c.verify(dep);;??
  • ??}??
  • }???

  • 代碼沒(méi)什么可說(shuō)的,就是最簡(jiǎn)單的singleton模式。?

    用這個(gè)組合子,我們可以對(duì)任意的Component做singleton。?

    下面接著說(shuō)monad。?

    有了bind,很多的功能都可以自然推演出來(lái)了。?

    比如我們前面用來(lái)刁難pico的那個(gè)例子,甚至,為了更強(qiáng)調(diào)復(fù)雜性,我們可以給B和A再另外增加一些參數(shù),這些參數(shù)要求從容器解析(畢竟,我們之所以需要容器,就是為了自動(dòng)解析一些依賴(lài)關(guān)系,要是全部依賴(lài)關(guān)系都hard-code,意義就不大了):?
    Java代碼??
  • void?A?createA();{??
  • ??B?b?=?new?B(...);;??
  • ??return?new?A(b,b,?...);;??
  • }??

  • 用bind,我們的思路可以是這樣:?
    1。用B的構(gòu)造函數(shù)生成一個(gè)Component。?
    2。這個(gè)Component生成一個(gè)對(duì)象,?
    3。這個(gè)產(chǎn)生的對(duì)象被傳遞給一個(gè)對(duì)應(yīng)A的Component當(dāng)作參數(shù)。這一步可以用bind來(lái)搞定。?


    Java代碼??
  • Component?b_component?=?Components.ctor(B.class);;??
  • return?new?BoundComponent(b_component,?new?Binder();{??
  • ??public?Component?bind(Object?b);{??
  • ????final?Component?arg?=?Components.value(b);;??
  • ????return?new?WithArgument(??
  • ??????new?WithArgument(a,?0,?arg);,??
  • ????1,?arg);;??
  • ??}??
  • });;??


  • Components.value(Object)是我們寫(xiě)的一個(gè)對(duì)ValueComponent的封裝靜態(tài)函數(shù)。?
    為了避免總寫(xiě)冗長(zhǎng)的new SomeComponent(...),我們把一些常用的基本Component都寫(xiě)成名字較短的靜態(tài)函數(shù),放在Components類(lèi)里面。?

    這樣,我們可以寫(xiě)Components.value(obj),而不是new ValueComponent(obj)。?
    要是覺(jué)得敲鍵盤(pán)還是麻煩,你甚至可以創(chuàng)建一個(gè)Components對(duì)象cc。然后到處用這個(gè)對(duì)象:?
    cc.value(obj)。舒服些了吧??


    從上面的例子,我們可以看到,那個(gè)直接創(chuàng)建對(duì)象的createA函數(shù)中的兩個(gè)步驟,在我們高階的Component中也被分為兩部。?
    而在兩個(gè)步驟之間的信息傳遞(那個(gè)b變量,從第一個(gè)步驟取得,然后在第二個(gè)步驟使用),則被用bind操作實(shí)現(xiàn)了。?

    到這,也許我們?cè)撋焐鞈醒?。舒服地往椅子背上一?#xff0c;說(shuō):“啊。終于干完了!我可以用高階邏輯來(lái)模擬任何直接硬編碼創(chuàng)建對(duì)象的邏輯了”。?

    這話(huà)倒也沒(méi)錯(cuò),有了bind,我們不再被局限于“構(gòu)造函數(shù)注射”,“setter注射”,“靜態(tài)工廠注射”等寥寥幾個(gè)注射方式;我們甚至可以對(duì)所謂的ioc type嗤之以鼻:“什么type1, type2?不過(guò)是我們可以處理的無(wú)數(shù)種情況中的幾種特例而已!”。?
    我們可以處理if-else,可以處理循環(huán),遞歸,任何可以直接用java寫(xiě)出來(lái)的對(duì)象創(chuàng)建方式,我們都可以在高階邏輯上得到對(duì)應(yīng)的組合版本,只要我們有足夠的原子組合子。(所謂原字組合子,不過(guò)是:FunctionComponent, BeanComponent,ValueComponent幾種)?

    比如,對(duì)應(yīng)于:?

    Java代碼??
  • X?createX();{??
  • ??A?a?=?A.instance(...);;??
  • ??if(a.isX(...););{??
  • ????return?new?X(...);;??
  • ??}??
  • ??else{??
  • ????return?new?Y(a,?...);.getX(...);;??
  • ??}??
  • }??

  • 這里,所有的省略號(hào)都代表可能需要從容器解析的參數(shù)。使用高階Component對(duì)象而不是直接調(diào)用createX()函數(shù)的一個(gè)原因,就是我們想要把依賴(lài)解析隱藏起來(lái)并且集中靈活地配置和管理。?


    對(duì)此,我們可以寫(xiě)成:?
    Java代碼??
  • Component?a_component?=?Components.static_method(A.class,?"instance");;??
  • return?new?BoundComponent(a_component,?new?Binder();{??
  • ??public?Component?bind(final?Object?a);{??
  • ????final?Component?isx_component?=?Components.method(a,?"isX");;??
  • ????return?new?BoundComponent(isx_component,?new?Binder();{??
  • ??????public?Component?bind(Object?isx);{??
  • ????????final?Boolean?v?=?(Boolean);isx;??
  • ????????if(v.booleanValue(););{??
  • ??????????return?Components.ctor(X.class);;??
  • ????????}??
  • ????????else{??
  • ??????????final?Coponent?y_component?=???
  • ???????????new?WithArgument(Components.ctor(Y.class);,?0,???
  • ??????????????Components.value(a););;??
  • ??????????return?new?BoundComponent(y_component,?new?Binder();{??
  • ????????????public?Component?bind(Object?y);{??
  • ??????????????return?Components.method(y,?"getX");;??
  • ????????????}??
  • ??????????});;??
  • ????????????
  • ????????}??
  • ??????}??
  • ????});;??
  • ??}??
  • });;??

  • 稍微有點(diǎn)繞,如果你到此有點(diǎn)糊涂的話(huà),請(qǐng)重溫一下前面的簡(jiǎn)單的bind的例子,只要體會(huì)了bind的具體意義,上面的代碼不過(guò)是幾層bind的嵌套。?


    好,如果你理解了bind,那么應(yīng)該能夠看懂上面的這段代碼了。它其實(shí)就是那個(gè)createX函數(shù)的嚴(yán)格翻譯。?

    功能確實(shí)很強(qiáng)大了,就是這代碼寫(xiě)起來(lái)這個(gè) 啊!對(duì)比一下createX和這個(gè)高階版本吧。我發(fā)現(xiàn)如果我多看幾眼這個(gè)所謂的"co"的代碼,我簡(jiǎn)直都要吐!如果說(shuō)createX這個(gè)函數(shù)的代碼是正常人說(shuō)話(huà),那么這個(gè)高階代碼就是唐僧念經(jīng):“南無(wú)阿彌陀佛,南無(wú)阿彌陀佛,南無(wú)阿彌陀佛...”,天啊!?


    如果我們真要Combinator-oriented起來(lái),難道要整天寫(xiě)這種蹩腳代碼?是不是我們吐啊吐的就會(huì)習(xí)慣了呢??
    pico的各個(gè)ComponentAdapter其實(shí)倒也就是這么寫(xiě),可是pico沒(méi)有bind,你很少需要寫(xiě)這么深的嵌套,甚至很少需要寫(xiě)匿名類(lèi)。?
    如果我們把我們的組件系統(tǒng)比喻作pascal語(yǔ)言的話(huà),pico的那些decorator充其量不過(guò)是一個(gè)dos的批處理,不,遠(yuǎn)不如批處理靈活,應(yīng)該也就是一個(gè)簡(jiǎn)單的用戶(hù)界面上的幾個(gè)按鈕。?

    那么有沒(méi)有什么辦法來(lái)簡(jiǎn)化語(yǔ)法呢??

    倒是有一個(gè)想法:?
    1。把Component從接口變成一個(gè)抽象類(lèi)。然后把一些常用的二元組合,比如bind,比如withArgument,withProperty,比如method,ifelse,都放在這個(gè)抽象類(lèi)里面。這樣,?

    我們就可以避免寫(xiě):?
    new SingletonComponent(c),而寫(xiě)c.singleton()。?
    我們就可以避免寫(xiě):?
    new BoundComponent(c1, ...),而寫(xiě):c1.bind(...)。?
    可以避免寫(xiě):?
    new WithArgument(c, 0, arg),而寫(xiě):c.withArgument(0, arg)。?
    可以避免寫(xiě):?
    Java代碼??
  • new?BoundComponent(c1,?new?Binder();{??
  • ??public?Component?bind(Object?obj);{??
  • ????return?Components.method(obj,?"method");;??
  • ??}??
  • });;??


  • 而寫(xiě)成:?
    Java代碼??
  • c1.method("method");;??


  • 可以避免寫(xiě):?
    Java代碼??
  • new?BoundComponent(c1,?new?Binder();{??
  • ??public?Component?bind(Object?obj);{??
  • ????if(((Boolean);obj);.booleanValue(););{??
  • ??????return?a;??
  • ????}??
  • ????else?return?b;??
  • ??}??
  • });;??

  • 而寫(xiě)成:?
    Java代碼??
  • c1.ifelse(a,b);;??

  • 等等等等。?

    這樣做,從架構(gòu)上確實(shí)有點(diǎn)損害,我們犧牲了“圍繞接口”的原則,而改為圍繞抽象類(lèi)了。?

    但是,從實(shí)際效果考慮,我發(fā)現(xiàn)它損失的架構(gòu)上的美感,遠(yuǎn)遠(yuǎn)比不上它帶來(lái)的編碼上的方便程度。誰(shuí)讓我們用的是java呢,世上沒(méi)有十全十美的事情,就湊合吧。?

    經(jīng)過(guò)這個(gè)改動(dòng),上面的對(duì)應(yīng)createX的高階代碼變成:?

    Java代碼??
  • Component?a_component?=?Components.static_method(A.class,?"instance");;??
  • return?a_component.bind(new?Binder();{??
  • ??public?Component?bind(final?Object?a);{??
  • ????final?Component?isx_component?=?Components.method(a,?"isX");;??
  • ????return?isx_component.ifelse(??
  • ??????Components.ctor(X.class);,??
  • ??????Components.ctor(Y.class);??
  • ????????.withArgument(0,?Components.value(a););??
  • ????????.method("getX");??
  • ????);;??
  • ??}??
  • });;??


  • 稍微好些了。而如果我們不需要給Y的構(gòu)造函數(shù)指定參數(shù),那么效果還會(huì)更好。?
    比如對(duì)?
    Java代碼??
  • X?createX();{??
  • ??A?a?=?A.instance(...);;??
  • ??if(a.isX(...););{??
  • ????return?new?X(...);;??
  • ??}??
  • ??else{??
  • ????return?new?Y(...);.getX(...);;??
  • ??}??
  • }??

  • 高階代碼會(huì)變成:?
    Java代碼??
  • Component?a_component?=?Components.static_method(A.class,?"instance");;??
  • return?a_component.method("isX");.ifelse(??
  • ????Components.ctor(X.class);,??
  • ????Components.ctor(Y.class);??
  • ??????.withArgument(0,?Components.value(a););??
  • ??????.method("getX");??
  • );;??

  • 又簡(jiǎn)潔了不少。?


    當(dāng)然,說(shuō)實(shí)話(huà),如果我們把情況任意復(fù)雜化,比如:?

    Java代碼??
  • Y?createY();{??
  • ??a?=?A.createA(...);;??
  • ??b?=?B.createB(a,?...);;??
  • ??c?=?C.createC(a,b,...);;??
  • ??return?Y.create(a,b,c,...);;??
  • }??

  • 要對(duì)createY寫(xiě)出高階對(duì)應(yīng)版本,這bind要嵌套三層,代碼無(wú)論如何不可能好看了。對(duì)此,我們只能聳聳肩說(shuō):無(wú)能為力了。因?yàn)槲覀冞@里已經(jīng)接觸到了java語(yǔ)言的底線。?

    值得欣慰的是,至少:?
    1。對(duì)簡(jiǎn)單需求,比如pico能夠處理的那些,我們的語(yǔ)法并不比pico麻煩。?
    2。對(duì)復(fù)雜需求,pico不能處理,而只能通過(guò)自己實(shí)現(xiàn)ComponentAdapter實(shí)現(xiàn);而我們的co構(gòu)建出來(lái)的系統(tǒng),在沒(méi)有剝奪你自己實(shí)現(xiàn)Component的前提下,也提供了采用聲明式的語(yǔ)法來(lái)組合的方式。至于是選擇用熟悉的java語(yǔ)法來(lái)過(guò)程式地自己處理依賴(lài),還是用聲明式的高階邏輯來(lái)仍然讓系統(tǒng)處理依賴(lài),則是程序員的自由了。?

    我們推薦,除非對(duì)非常復(fù)雜的需求,還是用聲明式的組合來(lái)處理更好。?


    寫(xiě)到這里,不得不嘮叨一些語(yǔ)言了。就象是你也可以在c這個(gè)過(guò)程語(yǔ)言里面使用一些oo的技巧一樣,我們?cè)趈ava這個(gè)oo語(yǔ)言里面是可以使用一些co的技巧的。?

    只不過(guò),缺乏語(yǔ)言上的良好支持,讓我們?cè)诓捎胏o設(shè)計(jì)的時(shí)候的代價(jià)有所增大。如何權(quán)衡?是co帶來(lái)的缺點(diǎn)(不方便調(diào)試,運(yùn)行效率低,語(yǔ)法麻煩)大,還是它帶來(lái)的好處(靈活應(yīng)對(duì)變化,減少代碼數(shù)量,方便重用)大,則是一個(gè)需要主觀經(jīng)驗(yàn)決定的事情了。?



    其實(shí),在一個(gè)真正支持monad組合子的語(yǔ)言里面,createY會(huì)被類(lèi)似寫(xiě)成這樣:?
    Java代碼??
  • do??
  • ??a?<-?static_method(A.class,?"createA");;??
  • ??b?<-?static_method(B.class,?"createB");??
  • ????.withArgument(0,?a);;??
  • ??c?<-?static_method(C.class,?"createC");??
  • ????.withArgument(0,?a);.withArgument(1,?b);;??
  • ??return?(static_method(Y.class,?"create");??
  • ????.withArgument(0,a);.withArgument(1,b);.withArgument(2,c);;??
  • ??);??


  • 所有的Binder匿名類(lèi)會(huì)被自動(dòng)生成。?
    這叫"do-notation",是haskell里面用來(lái)方便處理monad組合子的利器。?

    在我開(kāi)發(fā)的jaskell語(yǔ)言里面,對(duì)do-notation有類(lèi)似的支持。?


    題外話(huà):?
    最近,看到老莊設(shè)計(jì)的DJ里面說(shuō)要支持co。我覺(jué)得,如果僅僅象java這樣的所謂“支持”,那就和用C的函數(shù)指針號(hào)稱(chēng)支持OO一樣無(wú)趣了。?

    一個(gè)可以說(shuō)得上對(duì)co有支持的語(yǔ)言,即使不直接支持do-notation,也應(yīng)該把寫(xiě)匿名類(lèi)的代價(jià)降到和一個(gè)lamda函數(shù)相接近的程度。?
    即使我不能寫(xiě)?

    Java代碼??
  • a?<-?createA??
  • b?<-?createB?a??


  • 也要能夠?qū)懗?#xff1a;?

    Java代碼??
  • createA?>>=?\a->createB?a??



  • 組合并不僅僅是幾個(gè)簡(jiǎn)單的decorator套起來(lái)。真正復(fù)雜的co里,不同組合子之間是需要通過(guò)bind來(lái)通信的。而組合子之間的通信能力才是co強(qiáng)大的根源。


    from:?http://ajoo.iteye.com/blog/23326

    總結(jié)

    以上是生活随笔為你收集整理的论面向组合子程序设计方法 之 南无阿弥陀佛的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

    如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。