過(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)圖如下所示:
在這個(gè)例子中啸箫,有兩個(gè)類(lèi)比較重要。
-
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;
}
-
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ò)濾器模式的例子