1、背景
在实际的项目开发过程中,经常会遇到同一个业务操作不同场景时的不同业务逻辑,这个时候为了使系统拥有更高的可扩展性,可维护性,基于此背景开发了这套框架。
1、使用ServiceManager统一管理接口实例
2、使用ExecuteService统一接口实现,单一职责
3、可选AbstractExecuteServiceTemplate,使用它实现接口逻辑模板化,模板模式
4、可选ExecuteCommonService,接口实例通过聚合ExecuteCommonService达到代码复用的目的。合成复用原则。
1.1、以前
@Autowired
private AService aService;
@Autowired
private BService bService;
@Autowired
private CService cService;
@Autowired
private DService dService;
@Test
public void testOld() {
// 以往我们的多场景实现可能是这样
TestReq req = new TestReq();
TestRsp rsp = null;
if (场景A) {
rsp = aService.execute(req);
}
if (场景B) {
rsp = bService.execute(req);
}
if (场景C) {
rsp = cService.execute(req);
}
if (场景D) {
rsp = dService.execute(req);
}
}
1.2、现在
TestReq req = new TestReq();
ExecuteService<TestReq, TestRsp> serviceA = ServiceManager.getService(ServiceEnum.SERVICE_A, ServiceTypeEnum.TEST_SERVICE_A);
TestRsp rspA = serviceA.execute(req);
2、类图
核心接口为:ExecuteService,提供业务执行的入口;
接口实例管理器:ServiceManager,提供本地接口实例管理;
提供两种实现方式:
1、绿色标识为简单模式,适合接口逻辑比较独立,没有耦合的情况。
2、蓝色标识为复杂模式,ExecuteServiceTemplate将ExecuteService的execute方法模板化,规范ExecuteService实现。
额外提供一种代码复用的方式:
通过使用ExecuteCommonService将共用代码进行复用,然后聚合到ExecuteService实现中。
3、时序图
4、实现
4.1、鱼骨图
framework核心包为框架核心,为业务端提供规范与平台。
implement为业务端运用框架需要实现的类。
client为实际调用客户端,这里展示的为测试类。
4.2、framework
4.2.1、ExecuteService
package com.guo.core.framework.template;
import org.springframework.beans.factory.InitializingBean;
public interface ExecuteService<Req,Rsp> extends InitializingBean {
Rsp execute(Req req);
}
4.2.2、ServiceManager
package com.guo.core.framework.template;
import lombok.extern.slf4j.Slf4j;
import java.util.HashMap;
import java.util.Map;
@Slf4j
public class ServiceManager {
private static final Map<String, Map<String,ExecuteService<?,?>>> serviceMap = new HashMap<>();
public static void registerService(BizService service, ServiceType serviceType, ExecuteService<?,?> serviceImpl) {
log.info("服务[{}.{}]注册", service.getCode(),serviceType.getCode());
if (!serviceMap.containsKey(service.getCode())) {
Map<String,ExecuteService<?,?>> serviceTypeMap = new HashMap<>();
serviceTypeMap.putIfAbsent(serviceType.getCode(), serviceImpl);
serviceMap.putIfAbsent(service.getCode(), serviceTypeMap);
}
serviceMap.get(service.getCode()).putIfAbsent(serviceType.getCode(), serviceImpl);
}
public static ExecuteService getService(BizService service, ServiceType serviceType) {
Map<String,ExecuteService<?,?>> serviceTypeMap = serviceMap.get(service.getCode());
if (serviceTypeMap == null) {
log.info("服务[{}]不存在", service.getCode());
return null;
}
ExecuteService executeService = serviceTypeMap.get(serviceType.getCode());
if (executeService == null) {
log.info("服务[{}.{}]不存在", service.getCode(),serviceType.getCode());
return null;
}
return executeService;
}
}
4.2.3、Service
package com.guo.core.framework.template;
public interface BizService {
String getCode();
}
4.2.4、ServiceType
package com.guo.core.framework.template;
public interface ServiceType {
String getCode();
}
4.3、implement
4.3.1、简单模式
4.3.1.1、ServiceEnum
package com.guo.core.framework.template;
public enum ServiceEnum implements BizService {
SERVICE_A("SERVICE_A"),
SERVICE_B("SERVICE_B");
private final String code;
ServiceEnum(String code) {
this.code = code;
}
@Override
public String getCode() {
return this.code;
}
}
4.3.1.2、ServiceTypeEnum
package com.guo.core.framework.template;
public enum ServiceTypeEnum implements ServiceType {
TEST_SERVICE_A("TEST_SERVICE_A"),
TEST_SERVICE_B("TEST_SERVICE_B"),
TEST_SERVICE_C("TEST_SERVICE_C"),
TEST_SERVICE_D("TEST_SERVICE_D");
private final String code;
ServiceTypeEnum(String code) {
this.code = code;
}
@Override
public String getCode() {
return this.code;
}
}
4.3.1.3、TestReq
package com.guo.core.framework.template;
import lombok.Data;
@Data
public class TestReq {
private String name;
}
4.3.1.4、TestRsp
package com.guo.core.framework.template;
public class TestRsp {
}
4.3.1.5、AService
package com.guo.core.framework.template.simple;
import com.guo.core.framework.template.*;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@Slf4j
@Service
public class AService extends AbstractExecuteService<TestReq, TestRsp> {
@Autowired
private ExecuteCommonService executeCommonService;
@Override
protected ServiceType getServiceType() {
return ServiceTypeEnum.TEST_SERVICE_A;
}
@Override
protected BizService getService() {
return ServiceEnum.SERVICE_A;
}
@Override
public TestRsp execute(TestReq testReq) {
log.info("执行AService");
return executeCommonService.commonService(testReq);
}
}
4.3.1.5、BService
package com.guo.core.framework.template.simple;
import com.guo.core.framework.template.*;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@Slf4j
@Service
public class BService extends AbstractExecuteService<TestReq, TestRsp> {
@Autowired
private ExecuteCommonService executeCommonService;
@Override
protected ServiceType getServiceType() {
return ServiceTypeEnum.TEST_SERVICE_B;
}
@Override
protected BizService getService() {
return ServiceEnum.SERVICE_B;
}
@Override
public TestRsp execute(TestReq testReq) {
log.info("执行BService");
return executeCommonService.commonService(testReq);
}
}
4.3.1.6、ExecuteCommonService
package com.guo.core.framework.template;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
@Slf4j
@Service
public class ExecuteCommonService {
public TestRsp commonService(TestReq testReq) {
log.info("执行公共服务:commonService");
return new TestRsp();
}
}
4.3.1.7、集成测试
@Test
public void testSimple() {
// 简单模式
TestReq req = new TestReq();
ExecuteService<TestReq, TestRsp> serviceA = ServiceManager.getService(ServiceEnum.SERVICE_A, ServiceTypeEnum.TEST_SERVICE_A);
TestRsp rspA = serviceA.execute(req);
ExecuteService<TestReq, TestRsp> serviceB = ServiceManager.getService(ServiceEnum.SERVICE_B, ServiceTypeEnum.TEST_SERVICE_B);
TestRsp rspB = serviceB.execute(req);
}
4.3.2、复杂模式
4.3.2.1、ServiceEnum
package com.guo.core.framework.template;
public enum ServiceEnum implements BizService {
SERVICE_A("SERVICE_A"),
SERVICE_B("SERVICE_B");
private final String code;
ServiceEnum(String code) {
this.code = code;
}
@Override
public String getCode() {
return this.code;
}
}
4.3.2.2、ServiceTypeEnum
package com.guo.core.framework.template;
public enum ServiceTypeEnum implements ServiceType {
TEST_SERVICE_A("TEST_SERVICE_A"),
TEST_SERVICE_B("TEST_SERVICE_B"),
TEST_SERVICE_C("TEST_SERVICE_C"),
TEST_SERVICE_D("TEST_SERVICE_D");
private final String code;
ServiceTypeEnum(String code) {
this.code = code;
}
@Override
public String getCode() {
return this.code;
}
}
4.3.2.3、TestReq
package com.guo.core.framework.template;
import lombok.Data;
@Data
public class TestReq {
private String name;
}
4.3.2.4、TestRsp
package com.guo.core.framework.template;
public class TestRsp {
}
4.3.2.5、CService
package com.guo.core.framework.template.complex;
import com.guo.core.framework.template.*;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@Slf4j
@Service
public class CService extends ExecuteServiceTemplate {
@Autowired
private ExecuteCommonService executeCommonService;
@Override
protected ServiceType getServiceType() {
return ServiceTypeEnum.TEST_SERVICE_C;
}
@Override
protected BizService getService() {
return ServiceEnum.SERVICE_A;
}
@Override
protected void after(TestReq testReq, TestRsp testRsp) {
log.info("执行CService.after");
}
@Override
protected TestRsp post(TestReq testReq) {
log.info("执行CService.post");
return executeCommonService.commonService(testReq);
}
@Override
protected void before(TestReq testReq) {
log.info("执行CService.before");
}
}
4.3.2.5、DService
package com.guo.core.framework.template.complex;
import com.guo.core.framework.template.*;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@Slf4j
@Service
public class DService extends ExecuteServiceTemplate {
@Autowired
private ExecuteCommonService executeCommonService;
@Override
protected ServiceType getServiceType() {
return ServiceTypeEnum.TEST_SERVICE_D;
}
@Override
protected BizService getService() {
return ServiceEnum.SERVICE_B;
}
@Override
protected void after(TestReq testReq, TestRsp testRsp) {
log.info("执行DService.after");
}
@Override
protected TestRsp post(TestReq testReq) {
log.info("执行DService.post");
return executeCommonService.commonService(testReq);
}
@Override
protected void before(TestReq testReq) {
log.info("执行DService.before");
}
}
4.3.2.6、ExecuteServiceTemplate
package com.guo.core.framework.template.complex;
import com.guo.core.framework.template.AbstractExecuteService;
import com.guo.core.framework.template.TestReq;
import com.guo.core.framework.template.TestRsp;
public abstract class ExecuteServiceTemplate extends AbstractExecuteService<TestReq, TestRsp> {
@Override
public TestRsp execute(TestReq testReq) {
this.before(testReq);
TestRsp testRsp = this.post(testReq);
this.after(testReq, testRsp);
return testRsp;
}
protected abstract void after(TestReq testReq, TestRsp testRsp);
protected abstract TestRsp post(TestReq testReq);
protected abstract void before(TestReq testReq);
}
4.3.2.7、ExecuteCommonService
package com.guo.core.framework.template;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
@Slf4j
@Service
public class ExecuteCommonService {
public TestRsp commonService(TestReq testReq) {
log.info("执行公共服务:commonService");
return new TestRsp();
}
}
4.3.2.8、集成测试
@Test
public void testTemplate() {
// 模板模式
TestReq req = new TestReq();
ExecuteService<TestReq, TestRsp> serviceC = ServiceManager.getService(ServiceEnum.SERVICE_A, ServiceTypeEnum.TEST_SERVICE_C);
TestRsp rspC = serviceC.execute(req);
ExecuteService<TestReq, TestRsp> serviceD = ServiceManager.getService(ServiceEnum.SERVICE_B, ServiceTypeEnum.TEST_SERVICE_D);
TestRsp rspD = serviceD.execute(req);
}