转自:接口和面向接口编程
在刚开始做开发的时候,我并不是很理解接口和面向接口编程在实际开发中的作用,比如:
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 }
项目结构如下: