原文出处:
琴水玉
问题
可能很多开发者对“基于接口编程”的准则耳熟能详,也自觉不自觉地遵守着这条准则,可并不是真正明白为什么要这么做。大部分时候,我们定义Control, Service, Dao 接口,实际上却很少提供超过两个类的实现。 似乎只是照搬准则,过度设计,并未起实际效用。不过,基于接口设计与编程,在通常情形下可以增强方法的通用性;而在特定场景下,则可以有助于系统更好地重构和精炼。
当需要从一个系统提炼出更通用的系统,或者重构出一个新的系统时,预先设计的接口就会起大作用。
举个例子吧, 假设现在已经有一个订单导出的实现,如下所示:
package zzz.study.inf; import java.util.List; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import lombok.Data; /** * Created by shuqin on 18/3/29. */ public class OrderExportService { private static OrderExportService orderExportService; ExecutorService es = Executors.newFixedThreadPool(10); public static void main(String[] args) { getInstance().export(new OrderExportRequest()); } public static OrderExportService getInstance() { // 实际需要考虑并发, 或者通过Spring容器管理实例 if (orderExportService != null) { return orderExportService; } return new OrderExportService(); } public String exportOrder(OrderExportRequest orderExportRequest) { check(orderExportRequest); String exportId = save(orderExportRequest); generateJobFor(orderExportRequest); return exportId; } private String save(OrderExportRequest orderExportRequest) { // save export request param into db // return exportId return "123"; } private void generateJobFor(OrderExportRequest orderExportRequest) { es.execute(() -> exportFor(orderExportRequest)); } private void exportFor(OrderExportRequest orderExportRequest) { // export for orderExportRequest } private void check(OrderExportRequest orderExportRequest) { // check bizType // check source // check templateId // check shopId // check biz params } } @Data class OrderExportRequest { private String bizType; private String source; private String templateId; private String shopId; private String orderNos; private List<String> orderStates; }
可以看到,几乎所有的方法都是基于实现类来完成的。 如果这个系统就只需要订单导出也没什么问题,可是,如果你想提炼出一个更通用的导出,而这个导出的流程与订单导出非常相似,就尴尬了: 无法复用已有的代码和流程。它的代码类似这样:
package zzz.study.inf; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import lombok.Data; /** * Created by shuqin on 18/3/29. */ public class GeneralExportService { private static GeneralExportService generalExportService; ExecutorService es = Executors.newFixedThreadPool(10); public static void main(String[] args) { getInstance().export(new GeneralExportRequest()); } public static GeneralExportService getInstance() { // 实际需要考虑并发, 或者通过Spring容器管理实例 if (generalExportService != null) { return generalExportService; } return new GeneralExportService(); } public String exportOrder(GeneralExportRequest generalExportRequest) { check(generalExportRequest); String exportId = save(generalExportRequest); generateJobFor(generalExportRequest); return exportId; } private String save(GeneralExportRequest generalExportRequest) { // save export request param into db // return exportId return "123"; } private void generateJobFor(GeneralExportRequest generalExportRequest) { es.execute(() -> exportFor(generalExportRequest)); } private void exportFor(GeneralExportRequest orderExportRe