成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

基于Scala Trait的設(shè)計模式

開發(fā) 開發(fā)工具
之前,我重點介紹了那些已經(jīng)融入Scala語法的設(shè)計模式。今天要介紹的兩個設(shè)計模式,則主要與Scala的trait有關(guān)。

[[184365]]

《作為Scala語法糖的設(shè)計模式》中,我重點介紹了那些已經(jīng)融入Scala語法的設(shè)計模式。今天要介紹的兩個設(shè)計模式,則主要與Scala的trait有關(guān)。

Decorator Pattern

在GoF 23種設(shè)計模式中,Decorator Pattern算是一個比較特殊的模式。它充分利用了繼承和組合(或者委派)各自的優(yōu)勢,將它們混合起來,不僅讓優(yōu)勢擴大,還讓各自的缺點得到了抵消。Decorator模式的核心思想其實是“職責(zé)分離”,即將要裝飾的職責(zé)與裝飾的職責(zé)分離,從而使得它們可以在各自的繼承體系下獨立演化,然后通過傳遞對象(組合)的形式完成對被裝飾職責(zé)的重用。

從某種角度來講,裝飾職責(zé)與被裝飾職責(zé)之間的分離與各自抽象,不妨可以看做是Bridge模式的變種。但不同之處在于Decorator模式又額外地引入了繼承,但不是為了重用,而是為了多態(tài),使得裝飾者因為繼承自被裝飾者,從而擁有了被裝飾的能力。所以說,繼承的引入真真算得上是點睛之筆了。

理解Decorator模式,一定要理解繼承與組合各自扮演的角色。簡而言之,就是:

  • 繼承:裝飾者的多態(tài)
  • 組合:被裝飾者的重用

正因為此,在Java代碼中實現(xiàn)Decorator模式,要注意裝飾器類在重寫被裝飾器的業(yè)務(wù)行為時,一定要通過傳入的對象來調(diào)用被裝飾者的行為。假設(shè)傳入的被裝飾者對象為decoratee,則調(diào)用時就一定是decoratee,而不是super(由于繼承的關(guān)系,裝飾類是可以訪問super的)。

例如BufferedOutputStream類作為裝飾類,要裝飾OutputStream的write行為,就必須這樣實現(xiàn):

  1. public interface OutputStream { 
  2.     void write(byte b); 
  3.     void write(byte[] b); 
  4. public class FileOutputStream implements OutputStream { /* ... */ } 
  5. public class BufferedOutputStream extends OutputStream { 
  6.     //這里是組合的被裝飾者     
  7.     protected final OutputStream decoratee; 
  8.     public BufferedOutputStream(OutputStream decoratee) { 
  9.         this.decoratee = decoratee; 
  10.     } 
  11.  
  12.     public void write(byte b) { 
  13.         //這里應(yīng)該是調(diào)用decoratee, 而非super,雖然你可以訪問super     
  14.         decoratee.write(buffer) 
  15.     } 

然而,在Scala中實現(xiàn)Decorator模式,情況卻有些不同了。Scala的trait既體現(xiàn)了Java Interface的語義,卻又可以提供實現(xiàn)邏輯(相當(dāng)于Java 8的default interface),并在編譯時采用mixin方式完成代碼的重用。換言之,trait已經(jīng)***地融合了繼承與組合的各自優(yōu)勢。因此,在Scala中若要實現(xiàn)Decorator模式,只需要定義trait去實現(xiàn)裝飾者的功能即可:

  1. trait OutputStream { 
  2.   def write(b: Byte) 
  3.   def write(b: Array[Byte]) 
  4. class FileOutputStream(path: String) extends OutputStream { /* ... */ } 
  5. trait Buffering extends OutputStream { 
  6.   abstract override def write(b: Byte) { 
  7.     // ... 
  8.     super.write(buffer) 
  9.   } 

在Buffering的定義中,根本看不到組合的影子,且在對write方法進(jìn)行重寫時,調(diào)用的是super,這與我前面講到的內(nèi)容背道而馳啊!

區(qū)別在于組合(delegation)的時機。在Java(原諒我,因為使用Scala的緣故,我對Java 8的default interface沒有研究,不知道是否與scala的trait完全相同)語言中,組合是通過傳遞對象方式完成的職責(zé)委派與重用,也就是說,組合是在運行時發(fā)生的。Scala的實現(xiàn)則不然,在trait中利用abstract override關(guān)鍵字來完成一種stackable modifications,這種方式被稱之為Stackable Trait Pattern。這種語法僅能用于trait,它表示trait會將某個具體類針對該方法提供的實現(xiàn)混入(mixin)到trait中。裝飾的客戶端代碼如下:

  1. new FileOutputStream("foo.txt") with Buffering 

FileOutputStream的write方法實現(xiàn)在編譯時就被混入到Buffering中。所以可以稱這種組合為靜態(tài)組合。

Dependency Injection

Dependency Injection(依賴注入或者稱為IoC,即控制反轉(zhuǎn))其實應(yīng)該與依賴倒置原則結(jié)合起來理解,首先應(yīng)該保證不依賴于實現(xiàn)細(xì)節(jié),而是依賴于抽象(接口),然后,再考慮將具體依賴從類的內(nèi)部轉(zhuǎn)移到外面,并在運行時將依賴注入到類的內(nèi)部。這也是Dependency Injection的得名由來。

在Java世界,多數(shù)情況下我們會引入框架如Spring、Guice來完成依賴注入(這并不是說依賴注入一定需要框架,嚴(yán)格意義上,只要將依賴轉(zhuǎn)移到外面,然后通過set或者構(gòu)造器注入依賴,都可以認(rèn)為是實現(xiàn)了依賴注入),無論是基于xml配置,還是annotation,或者Groovy,核心思想都是將對象之間的依賴設(shè)置(裝配)轉(zhuǎn)交給框架來完成。Scala也有類似的IoC框架。但是,多數(shù)情況下,Scala程序員會充分利用trait與self type來實現(xiàn)所謂的依賴注入。這種設(shè)計模式在Scala中常常被昵稱為Cake Pattern。

一個典型的案例就是將一個Repository的實現(xiàn)注入到Service中。在Scala中,就應(yīng)該將Repository的抽象定義為trait,然后在具體的Service實現(xiàn)中,通過Self Type引入Repository:

  1. trait Repository { 
  2.   def save(user: User) 
  3. trait DatabaseRepository extends Repository { /* ... */ } 
  4. trait UserService {  
  5.   self: Repository =>  
  6.   def create(user: User) { 
  7.     //這里調(diào)用的是Repository的save方法 
  8.     //調(diào)用Self Type的方法就像調(diào)用自己的方法一般 
  9.     save(user) 
  10.   } 
  11.  
  12. //這里的with完成了對DatabaseRepository依賴的注入 
  13. new UserService with DatabaseRepository 

Cake Pattern遵循了Dependency Inject的要求,只是它沒有像Spring或者Guice那樣徹底將注入依賴的職責(zé)轉(zhuǎn)移給外部框架,而是將注入的權(quán)利交到了調(diào)用者手里。這樣會導(dǎo)致調(diào)用端代碼并沒有完全與具體依賴解耦,但在大多數(shù)情況下,這種輕量級的依賴注入方式,反而更討人喜歡。

在Scala開發(fā)中,我們常常會使用Cake Pattern。在我的一篇文章《一次設(shè)計演進(jìn)之旅》中,就引入了Cake Pattern來完成將ReportMetadata依賴的注入。

【本文為51CTO專欄作者“張逸”原創(chuàng)稿件,轉(zhuǎn)載請聯(lián)系原作者】

戳這里,看該作者更多好文

責(zé)任編輯:趙寧寧 來源: 51CTO專欄
相關(guān)推薦

2009-09-09 14:09:35

Scala Trait

2015-09-28 13:48:55

云計算設(shè)計模式負(fù)載均衡

2009-09-09 11:37:08

Scala的模式匹配

2009-07-08 16:42:57

Scala語言設(shè)計

2010-08-02 16:19:00

ibmdw面向?qū)ο?/a>

2021-04-19 21:25:48

設(shè)計模式到元

2009-07-08 12:43:59

Scala ServlScala語言

2013-12-04 14:19:40

JavaScript代碼重用

2021-02-01 10:01:58

設(shè)計模式 Java單例模式

2020-10-31 17:33:18

Scala語言函數(shù)

2010-09-14 15:34:41

Scala

2012-08-30 09:07:33

設(shè)計模式

2023-11-02 21:11:11

JavaScript設(shè)計模式

2012-07-10 01:59:12

設(shè)計模式

2021-12-29 10:38:35

運維框架KubeNest

2012-10-29 11:16:13

2011-12-15 01:12:59

ibmdw

2017-07-07 10:55:14

數(shù)據(jù)庫MongoDB設(shè)計模式

2022-01-19 08:21:12

設(shè)計裝飾器模式

2022-02-11 10:22:48

模版模式語言
點贊
收藏

51CTO技術(shù)棧公眾號

主站蜘蛛池模板: 亚洲综合色视频在线观看 | 91精品国产91久久久久久最新 | 精品欧美一区二区在线观看视频 | 国产aⅴ爽av久久久久久久 | 日韩av电影在线观看 | 国产成人精品久久二区二区91 | 欧美视频在线播放 | 一级毛片高清 | 美女中文字幕视频 | 国产欧美精品一区二区三区 | 91精品国产综合久久久亚洲 | 黄a免费网络 | 午夜手机在线 | 国产精品久久久久久久久久久久午夜片 | 久久精品亚洲精品国产欧美kt∨ | 在线视频第一页 | 99国产精品视频免费观看一公开 | 精品久久久久一区二区国产 | 久久久久久久国产精品影院 | 免费黄色日本 | 国产亚洲精品久久19p | 日日操视频 | 欧美日韩国产在线观看 | 成年人在线观看视频 | 国产精品jizz在线观看老狼 | 成人欧美一区二区三区黑人孕妇 | 欧美三级电影在线播放 | 久久一区二区三区四区五区 | 成人福利网| 成人在线观看免费爱爱 | 亚洲国产精品久久久 | 91免费电影 | 97精品久久 | 日本久久精品视频 | 毛片久久久 | av免费电影在线 | 91久久伊人 | 国产视频精品免费 | 国产极品粉嫩美女呻吟在线看人 | 午夜激情视频在线 | 久久久精|