在剛開始做開發的時候,我並不是很理解接口和面向接口編程在實際開發中的作用,比如:
1)為什么需要 Service、DAO 的接口;
2)為什么使用接口去引用依賴組件對象;
3)為什么花費很大力氣去設計對象工廠、對象容器,然后又把對象注入到依賴組件;
這些問題真是花了很長時間才搞清楚!
我們都知道,web 開發是分層的:控制層、業務層、數據層、實體類等,以業務層和數據層的依賴關系為例,通常可以使用三種方式來編寫代碼。
第一種:不編寫接口,直接在業務層使用數據層的類來使用,簡單粗暴、好理解
數據層類 xxDao = new 數據層類();
第二種:編寫接口和實現類,在業務層使用接口引用,但還是使用 new 關鍵字來實例化實現類對象,屬於脫褲子放屁類型。
數據層接口 xxDao = new 數據層實現類();
第三種:編寫接口和實現類,在程序啟動的時候使用“工廠”來管理對象,在業務層使用接口引用,然后從“工廠”獲取需要的對象,或者使用框架注入,這里涉及到了多態和反射。
數據層接口 xxDao = 工廠獲取/注入;
在不使用 Spring 或者自定義對象工廠的時候,前兩種方式都有可行,第二種方式可以為日后的架構設計升級提供一個接口規范,所以也是可以接受的。
在項目有了較大規模的時候,為了提高維護效率、實現組件之間的松耦合,我們會去設計“工廠”或者直接使用 Spring 來管理對象,這樣做的好處在於:
在整體修改了數據層實現類實現方式的時候(如:把 hibernate 改為 mybatis),不需要去修改業務層的任何代碼,只需要修改工廠配置文件即可實現組件的替換,因為任何一個符合“接口規范”的實現類對象都可以被注入到依賴該接口的業務類中去。
所以,我們有理由相信:反射、接口、多態是 Java 能夠成為動態編程語言的最主要原因。
在本文中,我們暫時不去看 Web 項目的組件解耦方案,之前有過一篇文章寫過自定義工廠的解耦方案,《多態和簡單對象工廠》,Spring 放到以后再去講解。
今天先用一個簡單的例子介紹一下反射、接口是如何提高程序擴展性、可維護性的。
我們的例子是這樣的:
1)有 20 個業務需要進行監控,分屬三個類型:A、B、C,每個類型的業務監控邏輯大致相同
2)以后可能會增加 D、E 業務類型
3)每個類型的業務數量也會隨着項目的擴大而增加
我們需要設計一個方案,確保在業務類型、業務增加時可以快速的配置上線
第一種設計方案:
1)編寫A、B、C三個類型的監控類代碼;
2)在遍歷全部業務時,分支結構判斷業務類型,不同的類型創建不同的監控類對象,調用監控方法
在我們的業務、業務類型增加時:需要增加相應的監控類;配置業務數據庫;修改分支結構。
如果有很多個業務類型,10個、20個,顯然分支結構有些不美觀。
所以還有一種使用接口和反射實現的方案。
第二種設計方案:
1)編寫業務監控接口,有一個 doMinitor 方法;
2)編寫 A、B、C 三個類型的監控類,實現業務監控接口;
3)在遍歷全部業務時,通過業務類型獲取到對應的業務監控實現類類型,實例化對象;
4)通過業務監控接口的引用調用業務監控實現類的 doMinitor 方法,對業務進行監控
在我們的業務、業務類型增加時:需要增加相應的監控類;配置業務數據庫。
所以,這個方案更加高大上。
我們簡單看一下編碼:
首先,Business 實體類用來保存業務信息
Business.java
1 public class Business { 2 3 private String businessName; 4 private String monitorPolicy; 5 6 public Business() { 7 super(); 8 } 9 10 public Business(String businessName, String monitorPolicy) { 11 super(); 12 this.businessName = businessName; 13 this.monitorPolicy = monitorPolicy; 14 } 15 16 public String getBusinessName() { 17 return businessName; 18 } 19 20 public void setBusinessName(String businessName) { 21 this.businessName = businessName; 22 } 23 24 public String getMonitorPolicy() { 25 return monitorPolicy; 26 } 27 28 public void setMonitorPolicy(String monitorPolicy) { 29 this.monitorPolicy = monitorPolicy; 30 } 31 }
接下來,編寫監控接口和三種類型業務的實現類
Monitor接口
1 public interface Monitor { 2 3 void doMonitor(Business business); 4 5 }
MonitorA類
1 public class MonitorA implements Monitor { 2 3 @Override 4 public void doMonitor(Business business) { 5 System.out.println("監控業務類型A------" + business.getBusinessName()); 6 } 7 }
MonitorB類
1 public class MonitorB implements Monitor { 2 3 @Override 4 public void doMonitor(Business business) { 5 System.out.println("監控業務類型B------" + business.getBusinessName()); 6 } 7 }
MonitorC類
1 public class MonitorC implements Monitor { 2 3 @Override 4 public void doMonitor(Business business) { 5 System.out.println("監控業務類型C------" + business.getBusinessName()); 6 } 7 }
最后,是 RunMonitor 入口類
1 public class RunMonitor { 2 3 private static List<Business> businessList = new ArrayList<Business>(); 4 5 static { 6 businessList.add(new Business("業務01", "org.net5ijy.monitor.policy.MonitorA")); 7 businessList.add(new Business("業務02", "org.net5ijy.monitor.policy.MonitorA")); 8 businessList.add(new Business("業務03", "org.net5ijy.monitor.policy.MonitorA")); 9 businessList.add(new Business("業務04", "org.net5ijy.monitor.policy.MonitorA")); 10 businessList.add(new Business("業務05", "org.net5ijy.monitor.policy.MonitorA")); 11 businessList.add(new Business("業務06", "org.net5ijy.monitor.policy.MonitorA")); 12 businessList.add(new Business("業務07", "org.net5ijy.monitor.policy.MonitorB")); 13 businessList.add(new Business("業務08", "org.net5ijy.monitor.policy.MonitorB")); 14 businessList.add(new Business("業務09", "org.net5ijy.monitor.policy.MonitorB")); 15 businessList.add(new Business("業務10", "org.net5ijy.monitor.policy.MonitorB")); 16 businessList.add(new Business("業務11", "org.net5ijy.monitor.policy.MonitorB")); 17 businessList.add(new Business("業務12", "org.net5ijy.monitor.policy.MonitorB")); 18 businessList.add(new Business("業務13", "org.net5ijy.monitor.policy.MonitorC")); 19 businessList.add(new Business("業務14", "org.net5ijy.monitor.policy.MonitorC")); 20 businessList.add(new Business("業務15", "org.net5ijy.monitor.policy.MonitorC")); 21 businessList.add(new Business("業務16", "org.net5ijy.monitor.policy.MonitorC")); 22 businessList.add(new Business("業務17", "org.net5ijy.monitor.policy.MonitorC")); 23 businessList.add(new Business("業務18", "org.net5ijy.monitor.policy.MonitorC")); 24 businessList.add(new Business("業務19", "org.net5ijy.monitor.policy.MonitorC")); 25 businessList.add(new Business("業務20", "org.net5ijy.monitor.policy.MonitorC"));33 } 34 35 public static void main(String[] args) { 36 37 for (Business business : businessList) { 38 String policyName = business.getMonitorPolicy(); 39 try { 40 Class<?> cls = Class.forName(policyName); 41 42 Monitor monitor = (Monitor) cls.newInstance(); 43 44 monitor.doMonitor(business); 45 46 } catch (ClassNotFoundException e) { 47 e.printStackTrace(); 48 } catch (InstantiationException e) { 49 e.printStackTrace(); 50 } catch (IllegalAccessException e) { 51 e.printStackTrace(); 52 } 53 } 54 } 55 }
項目結構如下:
過了一段時間,增加了業務類型 D、E,增加了五個業務,分屬 D、E,可以使用下面方式進行擴展:
MonitorD類
1 public class MonitorD implements Monitor { 2 3 @Override 4 public void doMonitor(Business business) { 5 System.out.println("監控業務類型D------" + business.getBusinessName()); 6 } 7 }
MonitorE類
1 public class MonitorE implements Monitor { 2 3 @Override 4 public void doMonitor(Business business) { 5 System.out.println("監控業務類型E------" + business.getBusinessName()); 6 } 7 }
項目結構如下: