函數(shù)式編程下的filter模式

過(guò)濾器模式,也稱為攔截器模式,還稱為管道模式。
有3個(gè)具有代表性的定義:
定義1.Bucshmann & Meunier 定義:過(guò)濾器和管道體系結(jié)構(gòu)風(fēng)格為處理數(shù)據(jù)流的系統(tǒng)提供了一種結(jié)構(gòu)渐排。每個(gè)處理步驟封裝在一個(gè)過(guò)濾器組件中妨蛹。數(shù)據(jù)通過(guò)相鄰過(guò)濾器之間的管道傳輸。重組過(guò)濾器可以建立相關(guān)系統(tǒng)族。
定義2.Shaw & Garlan定義: 管道和過(guò)濾器體系結(jié)構(gòu)風(fēng)格中的每個(gè)過(guò)濾器有一組輸入端和輸出端养叛。一個(gè)過(guò)濾器從輸入端讀取數(shù)據(jù)流,通過(guò)本地轉(zhuǎn)換和漸增計(jì)算,向輸出端輸出數(shù)據(jù)流种呐。管道充當(dāng)數(shù)據(jù)流的通道,將一個(gè)過(guò)濾器的輸出端連接到另一個(gè)過(guò)濾器的輸入端。
定義3. 信息管理系列委員會(huì)定義:在管道和過(guò)濾器軟件體系結(jié)構(gòu)中,每個(gè)模塊都有一組輸入和一組輸出弃甥。每個(gè)模塊從它的輸入端接收輸入數(shù)據(jù)流,在其內(nèi)部經(jīng)過(guò)處理后,按照標(biāo)準(zhǔn)的順序,將結(jié)果數(shù)據(jù)流送到輸出端,以達(dá)到傳遞一組完整的計(jì)算結(jié)果實(shí)例的目的爽室。通常情況下,可以通過(guò)對(duì)輸入數(shù)據(jù)流進(jìn)行局部變換,并采用漸增式計(jì)算方法,在未處理完所有輸入數(shù)據(jù)以前,就可以產(chǎn)生部分計(jì)算結(jié)果,并將其送到輸出端口(類(lèi)似于流水線結(jié)構(gòu))。因此,稱這種模塊為“過(guò)濾器“淆攻。在這種結(jié)構(gòu)中,各模塊之間的連接器充當(dāng)了數(shù)據(jù)流的導(dǎo)管,將一個(gè)過(guò)濾器的輸出傳到下一個(gè)過(guò)濾器的輸入端阔墩。所以,這種連接器稱為“管道”。
filter模式中有一個(gè)典型的例子瓶珊,其類(lèi)圖如下所示:

filter模式一個(gè)例子的類(lèi)圖
filter模式一個(gè)例子的類(lèi)圖

在這個(gè)例子中啸箫,有兩個(gè)類(lèi)比較重要。

  1. AbstractFilter類(lèi)
    它定義了如何組織過(guò)濾器鏈伞芹,主要是如下代碼:

    @Override
    public void setNext(Filter next) {

    this.next = next;
    

    }

    @Override
    public Filter getNext() {

    return this.next;
    

    }

    @Override
    public Filter getLast() {

    Filter last = this;
    while(last.getNext() != null)
    {
        last = last.getNext();
    }
    return last;
    

    }

  1. FilterChain類(lèi)
    它給出了一個(gè)添加過(guò)濾器類(lèi)和執(zhí)行過(guò)濾器鏈的接口:

    public void addFilter(Filter filter)
    {
    if(chain == null) chain = filter;
    else chain.getLast().setNext(filter);
    }

    public String execute(Order order)
    {
    if(chain != null) return chain.execute(order);
    else return "RUNNING...";
    }

整個(gè)實(shí)現(xiàn)過(guò)程相當(dāng)繁瑣忘苛,光過(guò)濾器的實(shí)現(xiàn),就寫(xiě)了5個(gè)類(lèi)唱较。
下面扎唾,我們來(lái)看看如何使用函數(shù)式編程實(shí)現(xiàn)該模式。
首先南缓,Order類(lèi)是不變的:

public class Order {
    private String name;
    private String contactNumber;
    private String address;
    private String depositNumber;
    private String order;
    public Order(String name, String contactNumber, String address, String depositNumber, String order) {
        super();
        this.name = name;
        this.contactNumber = contactNumber;
        this.address = address;
        this.depositNumber = depositNumber;
        this.order = order;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public String getContactNumber() {
        return contactNumber;
    }
    public void setContactNumber(String contactNumber) {
        this.contactNumber = contactNumber;
    }
    public String getAddress() {
        return address;
    }
    public void setAddress(String address) {
        this.address = address;
    }
    public String getDepositNumber() {
        return depositNumber;
    }
    public void setDepositNumber(String depositNumber) {
        this.depositNumber = depositNumber;
    }
    public String getOrder() {
        return order;
    }
    public void setOrder(String order) {
        this.order = order;
    }

}

接著胸遇,比較重要的改變是FilterChain類(lèi),代碼如下:

public class FilterChain {
private static List<Function<Order, String>> FILTERS = new ArrayList<>();
public void addFilter(Function<Order, String> filter)
{
    FILTERS.add(filter);
}
public String execute(Order order)
{
    if (FILTERS.isEmpty()) return "RUNNING...";
    StringBuilder sb = new StringBuilder();
    Collections.reverse(FILTERS);
    for (Function<Order, String> filter : FILTERS)
    {
        sb.append(filter.apply(order));
    }
    return sb.toString();
}

}

在上述代碼中汉形,我們使用List<Function<Order, String>>做一個(gè)管道狐榔,這是因?yàn)镾tream對(duì)象能夠做管道對(duì)象的任何事情。
管道里面流動(dòng)的是Order對(duì)象获雕,每一個(gè)管道的處理函數(shù)是Function<Order, String>薄腻,這是因?yàn)樵嫉奶幚砗瘮?shù)String execute(Order order);只有一個(gè)輸入?yún)?shù)和一個(gè)輸出參數(shù),剛好可以使用Function函數(shù)來(lái)處理届案。如果有多個(gè)輸入?yún)?shù)庵楷,那么請(qǐng)重新定義一個(gè)函數(shù)式接口即可。
這樣一來(lái)楣颠,增加過(guò)濾器類(lèi)就編程了增加Function函數(shù)了:

public void addFilter(Function<Order, String> filter)
{
    FILTERS.add(filter);
}

過(guò)濾器鏈的執(zhí)行尽纽,也就是順序執(zhí)行FILTERS里面的元素即可:

for (Function<Order, String> filter : FILTERS)
{
    sb.append(filter.apply(order));
}

然后是FilterManager類(lèi)也會(huì)有少許改變:

public class FilterManager {
    private FilterChain filterChain;
    public FilterManager(FilterChain filterChain) {
        super();
        this.filterChain = filterChain;
    }
    public void addFilter(Function<Order, String> filter)
    {
        filterChain.addFilter(filter);
    }
    public String filterRequest(Order order)
    {
        return filterChain.execute(order);
    }

}

相對(duì)簡(jiǎn)單,這里就不多說(shuō)了童漩。
最后弄贿,我們來(lái)看如何使用這個(gè)過(guò)濾器模式。
首先是添加過(guò)濾器:

FilterManager manager = new FilterManager(new FilterChain());
manager.addFilter((o -> {
    if(o.getAddress() == null||o.getAddress().isEmpty())
    {
        return "Invalid address!";
    }
    return "";
}));

manager.addFilter((o) ->{
    if(o.getContactNumber() == null ||
            o.getContactNumber().isEmpty()||
            o.getContactNumber().matches(".*[^\\d]+.*")||
            o.getContactNumber().length() != 11)
    {
        return "Invalid contact number!";
    }
    else return "";
});

manager.addFilter((o) -> {
    if(o.getDepositNumber() == null || o.getDepositNumber().isEmpty())
    {
        return "invalid deposit number!";
    }
    else return "";
});

manager.addFilter((o) -> {
    if(o.getName() == null || o.getName().isEmpty() || o.getName().matches(".*[^\\w|\\s]+.*"))
    {
       return "Invalid name!";
    }
    else return "";
});

manager.addFilter((o) -> {
    if(o.getOrder() == null ||o.getOrder().isEmpty())
    {
        return "Invalid order!";
    }
    else return "";
});

最后是執(zhí)行過(guò)濾器:

Order order = new Order("Tom","201244","Hangzhou Yuhang","203",null);
System.out.println(manager.filterRequest(order));

怎么樣矫膨?這就是一個(gè)使用了函數(shù)式編程的過(guò)濾器模式的完整實(shí)現(xiàn)過(guò)程差凹,是不是使用了函數(shù)式編程期奔,可以大大的減少了類(lèi)的冗余?


參考文獻(xiàn):github上關(guān)于過(guò)濾器模式的例子

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末危尿,一起剝皮案震驚了整個(gè)濱河市呐萌,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌谊娇,老刑警劉巖肺孤,帶你破解...
    沈念sama閱讀 211,743評(píng)論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異济欢,居然都是意外死亡赠堵,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,296評(píng)論 3 385
  • 文/潘曉璐 我一進(jìn)店門(mén)法褥,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)茫叭,“玉大人,你說(shuō)我怎么就攤上這事挖胃≡影校” “怎么了梆惯?”我有些...
    開(kāi)封第一講書(shū)人閱讀 157,285評(píng)論 0 348
  • 文/不壞的土叔 我叫張陵酱鸭,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我垛吗,道長(zhǎng)凹髓,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 56,485評(píng)論 1 283
  • 正文 為了忘掉前任怯屉,我火速辦了婚禮蔚舀,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘锨络。我一直安慰自己赌躺,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,581評(píng)論 6 386
  • 文/花漫 我一把揭開(kāi)白布羡儿。 她就那樣靜靜地躺著礼患,像睡著了一般。 火紅的嫁衣襯著肌膚如雪掠归。 梳的紋絲不亂的頭發(fā)上缅叠,一...
    開(kāi)封第一講書(shū)人閱讀 49,821評(píng)論 1 290
  • 那天,我揣著相機(jī)與錄音虏冻,去河邊找鬼肤粱。 笑死,一個(gè)胖子當(dāng)著我的面吹牛厨相,可吹牛的內(nèi)容都是我干的领曼。 我是一名探鬼主播鸥鹉,決...
    沈念sama閱讀 38,960評(píng)論 3 408
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼悯森!你這毒婦竟也來(lái)了宋舷?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 37,719評(píng)論 0 266
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤瓢姻,失蹤者是張志新(化名)和其女友劉穎祝蝠,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體幻碱,經(jīng)...
    沈念sama閱讀 44,186評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡绎狭,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,516評(píng)論 2 327
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了褥傍。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片儡嘶。...
    茶點(diǎn)故事閱讀 38,650評(píng)論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖恍风,靈堂內(nèi)的尸體忽然破棺而出蹦狂,到底是詐尸還是另有隱情,我是刑警寧澤朋贬,帶...
    沈念sama閱讀 34,329評(píng)論 4 330
  • 正文 年R本政府宣布凯楔,位于F島的核電站,受9級(jí)特大地震影響锦募,放射性物質(zhì)發(fā)生泄漏摆屯。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,936評(píng)論 3 313
  • 文/蒙蒙 一糠亩、第九天 我趴在偏房一處隱蔽的房頂上張望虐骑。 院中可真熱鬧,春花似錦赎线、人聲如沸廷没。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,757評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)颠黎。三九已至,卻和暖如春矫废,著一層夾襖步出監(jiān)牢的瞬間盏缤,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 31,991評(píng)論 1 266
  • 我被黑心中介騙來(lái)泰國(guó)打工蓖扑, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留唉铜,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 46,370評(píng)論 2 360
  • 正文 我出身青樓律杠,卻偏偏與公主長(zhǎng)得像潭流,于是被迫代替她去往敵國(guó)和親竞惋。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,527評(píng)論 2 349

推薦閱讀更多精彩內(nèi)容

  • Spring Cloud為開(kāi)發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見(jiàn)模式的工具(例如配置管理灰嫉,服務(wù)發(fā)現(xiàn)拆宛,斷路器,智...
    卡卡羅2017閱讀 134,633評(píng)論 18 139
  • 本文包括:1讼撒、Filter簡(jiǎn)介2浑厚、Filter是如何實(shí)現(xiàn)攔截的?3根盒、Filter開(kāi)發(fā)入門(mén)4钳幅、Filter的生命周期...
    廖少少閱讀 7,256評(píng)論 3 56
  • 歸納式查經(jīng) 觀察:這段經(jīng)文在說(shuō)什么 經(jīng)文大意 瑪拿西支派所得的地,其中特別說(shuō)西羅非哈的女兒們炎滞,以及他們沒(méi)有趕出迦南...
    MTD學(xué)院閱讀 21,882評(píng)論 0 0
  • 我總是想出去多培訓(xùn)敢艰,學(xué)習(xí)〔崛可是又害怕坐車(chē)钠导,最后學(xué)習(xí)的心還是戰(zhàn)勝了恐懼。千課萬(wàn)人真的是一個(gè)很棒的學(xué)習(xí)平臺(tái)森瘪,這是我第一...
    iris加油閱讀 126評(píng)論 0 0
  • (今日午后的一場(chǎng)暴雨牡属,導(dǎo)致了多年少見(jiàn)的降雨量,上方半山中一水庫(kù)水位暴漲溢出堤壩柜砾,水淹家園湃望。傍晚時(shí)分换衬,政府部門(mén)動(dòng)員我...
    唯一還是我閱讀 284評(píng)論 22 12