抽象工厂模式和工厂方法模式虽然主要的目的都是为了解决接口选择问题。 但是在实现上, 抽象工厂是一个中心工厂, 它能够创建其他的工厂。
业务背景介绍
随着业务超过预期的快速发展,系统的负载能力也要随着跟上。原有的单机 Redis 已经满足不了系统需求。这时候就需要更换为更为健壮的Redis集群服务,虽然需要修改但是不能影响目前系统的运行,还要平滑过渡过去。
随着这次的升级,可以预见的问题会有;
- 很多服务用到了Redis需要一起升级到集群。
- 需要兼容集群A和集群B,便于后续的灾备。
- 两套集群提供的接口和方法各有差异,需要做适配。
- 不能影响到目前正常运行的系统。
单机的Redis服务操作
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
|
public class RedisUtils {
private Logger logger = LoggerFactory.getLogger(RedisUtils.class);
private Map<String, String> dataMap = new ConcurrentHashMap<String, String>();
public String get(String key) { logger.info("Redis获取数据 key:{}", key); return dataMap.get(key); }
public void set(String key, String value) { System.out.println("写数据"); logger.info("Redis写入数据 key:{} val:{}", key, value); dataMap.put(key, value); }
public void set(String key, String value, long timeout, TimeUnit timeUnit) { logger.info("Redis写入数据 key:{} val:{} timeout:{} timeUnit:{}", key, value, timeout, timeUnit.toString()); dataMap.put(key, value); }
public void del(String key) { logger.info("Redis删除数据 key:{}", key); dataMap.remove(key); }
}
|
业务实现逻辑
准备了两种集群, EGM 和 IIR
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
| public class EGM { private Logger logger = LoggerFactory.getLogger(IIR.class);
private Map<String, String> dataMap = new ConcurrentHashMap<String, String>();
public String get(String key) { logger.info("IIR获取数据 key:{}", key); return dataMap.get(key); }
public void set(String key, String value) { logger.info("IIR写入数据 key:{} val:{}", key, value); dataMap.put(key, value); }
public void setExpire(String key, String value, long timeout, TimeUnit timeUnit) { logger.info("IIR写入数据 key:{} val:{} timeout:{} timeUnit:{}", key, value, timeout, timeUnit.toString()); dataMap.put(key, value); }
public void del(String key) { logger.info("IIR删除数据 key:{}", key); dataMap.remove(key); } }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
| @Slf4j public class IIR { private Logger logger = LoggerFactory.getLogger(IIR.class); private Map<String, String> dataMap= new ConcurrentHashMap<>();
public String gain(String key) { logger.info("EGM获取数据 key:{}", key); return dataMap.get(key); }
public void set(String key, String value) { logger.info("EGM写入数据 key:{} val:{}", key, value); dataMap.put(key, value); }
public void setEx(String key, String value, long timeout, TimeUnit timeUnit) { logger.info("EGM写入数据 key:{} val:{} timeout:{} timeUnit:{}", key, value, timeout, timeUnit.toString()); dataMap.put(key, value); }
public void delete(String key) { logger.info("EGM删除数据 key:{}", key); dataMap.remove(key); }
}
|
两个适配器的实现:
都实现了ICacheAdapter适配器接口,也是为了统一适配器的服务
EGMCacheAdapter
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
|
public class EGMCacheAdapter implements ICacheAdapter { private EGM egm = new EGM();
public String get(String key) { return egm.gain(key); }
public void set(String key, String value) { egm.set(key, value); }
public void set(String key, String value, long timeout, TimeUnit timeUnit) { egm.setEx(key, value, timeout, timeUnit); }
public void del(String key) { egm.delete(key); } }
|
IIRCacheAdapter
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
|
public class IIRCacheAdapter implements ICacheAdapter {
private IIR iir = new IIR();
public String get(String key) { return iir.get(key); }
public void set(String key, String value) { System.out.println("写书据"); iir.set(key, value); }
public void set(String key, String value, long timeout, TimeUnit timeUnit) { iir.setExpire(key, value, timeout, timeUnit); }
public void del(String key) { iir.del(key); } }
|
定义服务的统一入口
定义了CacheService作为服务的统一接口, (这里为了服务入口的统一才实现了接口, 其实也可以不用)
并且CacheService中实现的方法应该要和适配器接口中实现的一样, 这样才能够通过invoke找得到适配器中的方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14
|
public interface CacheService {
String get(final String key);
void set(String key, String value);
void set(String key, String value, long timeout, TimeUnit timeUnit);
void del(String key); }
|
同时还需要实现统一接口的实现类, 这样才能够拿到服务对象。
这里就不做实现了, 和前面的单体实现redis一样
通过代理类调用对象方法的流程
JDK接口 代理的抽象工厂getProxy
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
|
public class JDKProxy {
public static <T> T getProxy(Class<T> interfaceClass, ICacheAdapter cacheAdapter) throws Exception { InvocationHandler handler = new JDKInvocationHandler(cacheAdapter); ClassLoader classLoader = Thread.currentThread().getContextClassLoader(); Class<?>[] classes = interfaceClass.getInterfaces(); return (T) Proxy.newProxyInstance(classLoader, classes, handler); } }
|
抽象工厂代理的实现
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
|
public class JDKInvocationHandler implements InvocationHandler {
private ICacheAdapter cacheAdapter;
public JDKInvocationHandler(ICacheAdapter cacheAdapter) { this.cacheAdapter = cacheAdapter; }
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("调用希望调用的方法: " + method.getName() + " 并且传递参数 "); return ICacheAdapter.class.getMethod(method.getName(), ClassLoaderUtils.getClazzByArgs(args)).invoke(cacheAdapter, args); }
}
|
抽象工厂模式的代理类抽象场景测试
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| @Test public void test_Factory() throws Exception { CacheService proxy_EGM = JDKProxy.getProxy(CacheServiceImpl.class, new EGMCacheAdapter()); System.out.println("完成代理对象的获取"); proxy_EGM.set("user-EGM", "rayce-EGM"); System.out.println("完成代理方法的调用"); String val01 = proxy_EGM.get("user-EGM"); System.out.println("测试结果:" + val01);
CacheService proxy_IIR = JDKProxy.getProxy(CacheServiceImpl.class, new IIRCacheAdapter()); proxy_IIR.set("user-IIR", "rayce-IIR"); String val02 = proxy_IIR.get("user-IIR"); System.out.println("测试结果:" + val02);
}
|