抽象工厂模式介绍抽象工厂模式的实战
不使用抽象工厂模式的写法使用抽象工厂模式的写法
定义适配接口创建不同集群缓存的实现创建代理类 抽象工厂在Spring中的应用
抽象工厂模式介绍抽象工厂模式是创建其他工厂的模式.
一个标准(接口)有不同的实现.
案例是采用系统中有不同的缓存服务.
对不同的缓存服务做适配.
创建tutorials-5.0-0 模块
pom中如下
4.0.0 org.example 1.0-SNAPSHOT tutorials-5.0-0 com.alibaba fastjson 1.2.62 junit junit 4.12 test org.slf4j slf4j-api 1.7.5 org.slf4j jcl-over-slf4j 1.7.5 ch.qos.logback logback-classic 1.0.9 slf4j-api org.slf4j
创建一个RedisUtils 缓存工具类, 实现缓存的增删改查功能.
public class RedisUtils {
private Logger logger = LoggerFactory.getLogger(RedisUtils.class);
private Map dataMap = new ConcurrentHashMap();
public String get(String key) {
logger.info(" redis 获取数据 key: {}", key);
return dataMap.get(key);
}
public void set(String key, String value) {
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);
}
}
CacheService 缓存服务的接口
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);
}
缓存服务的实现类CacheServiceImpl
public class CacheServiceImpl implements CacheService {
private RedisUtils redisUtils = new RedisUtils();
public String get(String key) {
return redisUtils.get(key);
}
public void set(String key, String value) {
redisUtils.set(key, value);
}
public void set(String key, String value, long timeout, TimeUnit timeUnit) {
redisUtils.set(key, value, timeout, timeUnit);
}
public void del(String key) {
redisUtils.del(key);
}
}
EGM 类实现EGM的缓存服务
public class EGM {
private Logger logger = LoggerFactory.getLogger(EGM.class);
private Map 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);
}
}
IIR 实现IIR的缓存服务
public class IIR {
private Logger logger = LoggerFactory.getLogger(IIR.class);
private Map dataMap = new ConcurrentHashMap();
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);
}
}
tutorials-5.0-1 创建改模块, 用于在不使用设计模式时的缓存兼容.
pom如下: 引用了tutorials-5.0-0
mydesign-study org.example 1.0-SNAPSHOT 4.0.0 tutorials-5.0-1 com.alibaba fastjson 1.2.62 junit junit 4.12 test org.slf4j slf4j-api 1.7.5 org.slf4j jcl-over-slf4j 1.7.5 ch.qos.logback logback-classic 1.0.9 slf4j-api org.slf4j org.example 1.0-SNAPSHOT tutorials-5.0-0
创建CacheService接口
public interface CacheService {
String get(final String key, int redisType);
void set(String key, String value, int redisType);
void set(String key, String value, long timeout, TimeUnit timeUnit, int redisType);
void del(String key, int redisType);
}
创建CacheServiceImpl 类如下 , 用if else去判断不同的实现缓存
package com.thc.design.cuisine.impl;
import com.thc.design.CacheService;
import com.thc.design.RedisUtils;
import com.thc.design.matter.EGM;
import com.thc.design.matter.IIR;
import java.util.concurrent.TimeUnit;
public class CacheServiceImpl implements CacheService {
private RedisUtils redisUtils = new RedisUtils();
private EGM egm = new EGM();
private IIR iir = new IIR();
public String get(String key, int redisType) {
if (1 == redisType) {
return egm.gain(key);
}
if (2 == redisType) {
return iir.get(key);
}
return redisUtils.get(key);
}
public void set(String key, String value, int redisType) {
if (1 == redisType) {
egm.set(key, value);
return;
}
if (2 == redisType) {
iir.set(key, value);
}
}
public void set(String key, String value, long timeout, TimeUnit timeUnit, int redisType) {
if (1 == redisType) {
egm.setEx(key, value, timeout, timeUnit);
}
if (2 == redisType) {
iir.setExpire(key, value, timeout, timeUnit);
}
redisUtils.set(key, value, timeout, timeUnit);
}
public void del(String key, int redisType) {
if (1 == redisType) {
egm.delete(key);
return;
}
if (2 == redisType) {
iir.del(key);
return;
}
redisUtils.del(key);
}
}
创建测试类ApiTest
public class ApiTest {
@Test
public void test_cacheService() {
CacheService cacheService = new CacheServiceImpl();
cacheService.set("user_name1", "周杰伦", 1);
String value = cacheService.get("user_name1", 1);
System.out.println("测试结果: "+ value);
cacheService.set("user_name2", "周润发", 2);
String value2 = cacheService.get("user_name2", 2);
System.out.println("测试结果: "+ value2);
}
}
控制台打印如下
21:52:10.966 [main] INFO com.thc.design.matter.EGM - EGM 写入数据 key: user_name1 , val : 周杰伦
21:52:10.968 [main] INFO com.thc.design.matter.EGM - EGM获取数据 key: user_name1
测试结果: 周杰伦
21:52:10.969 [main] INFO com.thc.design.matter.IIR - IIR写入数据 key:user_name2 val:周润发
21:52:10.969 [main] INFO com.thc.design.matter.IIR - IIR获取数据 key: user_name2
测试结果: 周润发
可以看到通过传递type 不同, 实现了走不同的缓存 .
使用抽象工厂模式的写法 定义适配接口ICacheAdapter
public interface ICacheAdapter {
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);
}
创建不同集群缓存的实现
EGMCacheAdapter
import java.util.concurrent.TimeUnit;
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
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) {
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);
}
}
创建代理类
public class JDKProxy {
// jdk动态代理 通过类加载器获取类
public static T getProxy(Class interfaceClass, ICacheAdapter cacheAdapter) {
InvocationHandler handler = new JDKInvocationHandler(cacheAdapter);
ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
Class>[] classes = interfaceClass.getInterfaces();
return (T) Proxy.newProxyInstance(classLoader, new Class[]{classes[0]}, handler);
}
}
创建类加载器工具类
package com.thc.design.util;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.*;
import java.util.concurrent.TimeUnit;
public class ClassLoaderUtils {
private static Set primitiveSet = new HashSet();
static {
primitiveSet.add(Integer.class);
primitiveSet.add(Long.class);
primitiveSet.add(Float.class);
primitiveSet.add(Byte.class);
primitiveSet.add(Short.class);
primitiveSet.add(Double.class);
primitiveSet.add(Character.class);
primitiveSet.add(Boolean.class);
}
public static ClassLoader getCurrentClassLoader() {
ClassLoader cl = Thread.currentThread().getContextClassLoader();
if (cl == null) {
cl = ClassLoaderUtils.class.getClassLoader();
}
return cl == null ? ClassLoader.getSystemClassLoader() : cl;
}
public static ClassLoader getClassLoader(Class> clazz) {
ClassLoader loader = Thread.currentThread().getContextClassLoader();
if (loader != null) {
return loader;
}
if (clazz != null) {
loader = clazz.getClassLoader();
if (loader != null) {
return loader;
}
return clazz.getClassLoader();
}
return ClassLoader.getSystemClassLoader();
}
public static Class forName(String className)
throws ClassNotFoundException {
return forName(className, true);
}
public static Class forName(String className, boolean initialize)
throws ClassNotFoundException {
return Class.forName(className, initialize, getCurrentClassLoader());
}
public static Class forName(String className, ClassLoader cl)
throws ClassNotFoundException {
return Class.forName(className, true, cl);
}
public static T newInstance(Class clazz) throws Exception {
if (primitiveSet.contains(clazz)) {
return null;
}
if (clazz.isMemberClass() && !Modifier.isStatic(clazz.getModifiers())) {
Constructor constructorList[] = clazz.getDeclaredConstructors();
Constructor defaultConstructor = null;
for (Constructor con : constructorList) {
if (con.getParameterTypes().length == 1) {
defaultConstructor = con;
break;
}
}
if (defaultConstructor != null) {
if (defaultConstructor.isAccessible()) {
return (T) defaultConstructor.newInstance(new Object[]{null});
} else {
try {
defaultConstructor.setAccessible(true);
return (T) defaultConstructor.newInstance(new Object[]{null});
} finally {
defaultConstructor.setAccessible(false);
}
}
} else {
throw new Exception("The " + clazz.getCanonicalName() + " has no default constructor!");
}
}
try {
return clazz.newInstance();
} catch (Exception e) {
Constructor constructor = clazz.getDeclaredConstructor();
if (constructor.isAccessible()) {
throw new Exception("The " + clazz.getCanonicalName() + " has no default constructor!", e);
} else {
try {
constructor.setAccessible(true);
return constructor.newInstance();
} finally {
constructor.setAccessible(false);
}
}
}
}
public static Class>[] getClazzByArgs(Object[] args) {
Class>[] parameterTypes = new Class[args.length];
for (int i = 0; i < args.length; i++) {
if (args[i] instanceof ArrayList) {
parameterTypes[i] = List.class;
continue;
}
if (args[i] instanceof linkedList) {
parameterTypes[i] = List.class;
continue;
}
if (args[i] instanceof HashMap) {
parameterTypes[i] = Map.class;
continue;
}
if (args[i] instanceof Long){
parameterTypes[i] = long.class;
continue;
}
if (args[i] instanceof Double){
parameterTypes[i] = double.class;
continue;
}
if (args[i] instanceof TimeUnit){
parameterTypes[i] = TimeUnit.class;
continue;
}
parameterTypes[i] = args[i].getClass();
}
return parameterTypes;
}
public Method getMethod(Class> classType, String methodName, Class>... parameterTypes) throws NoSuchMethodException {
return classType.getMethod(methodName, parameterTypes);
}
}
创建JDKInvocationHandler 反射执行方法
package com.thc.design.factory;
import com.thc.design.util.ClassLoaderUtils;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
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 {
return ICacheAdapter.class.getMethod(method.getName(), ClassLoaderUtils.getClazzByArgs(args)).invoke(cacheAdapter, args);
}
}
创建CacheServiceImpl
import com.thc.design.CacheService;
import com.thc.design.RedisUtils;
import java.util.concurrent.TimeUnit;
public class CacheServiceImpl implements CacheService {
private RedisUtils redisUtils = new RedisUtils();
public String get(String key) {
return redisUtils.get(key);
}
public void set(String key, String value) {
redisUtils.set(key, value);
}
public void set(String key, String value, long timeout, TimeUnit timeUnit) {
redisUtils.set(key, value, timeout, timeUnit);
}
public void del(String key) {
redisUtils.del(key);
}
}
创建测试类
import com.thc.design.factory.JDKProxy;
import com.thc.design.factory.impl.EGMCacheAdapter;
import com.thc.design.factory.impl.IIRCacheAdapter;
import com.thc.design.impl.CacheServiceImpl;
import org.junit.Test;
public class ApiTest {
@Test
public void test_CacheService() throws Exception {
CacheService proxy_EGM = JDKProxy.getProxy(CacheServiceImpl.class, new EGMCacheAdapter());
proxy_EGM.set("user_name_01", "林俊杰");
String val01 = proxy_EGM.get("user_name_01");
System.out.println("测试结果: " + val01);
CacheService proxy_IIR = JDKProxy.getProxy(CacheServiceImpl.class, new IIRCacheAdapter());
proxy_IIR.set("user_name_02", "苏有朋");
String val02 = proxy_IIR.get("user_name_02");
System.out.println("测试结果: "+val02);
}
}
控制台打印如下 :
22:02:30.050 [main] INFO com.thc.design.matter.EGM - EGM 写入数据 key: user_name_01 , val : 林俊杰
22:02:30.054 [main] INFO com.thc.design.matter.EGM - EGM获取数据 key: user_name_01
测试结果: 林俊杰
22:02:30.055 [main] INFO com.thc.design.matter.IIR - IIR写入数据 key:user_name_02 val:苏有朋
22:02:30.055 [main] INFO com.thc.design.matter.IIR - IIR获取数据 key: user_name_02
测试结果: 苏有朋
成功通过动态代理和抽象工厂模式实现了对不同缓存的使用.
抽象工厂在Spring中的应用Spring中的BeanFactory是一个顶级的抽象工厂.
其底层实现类中, 有两个类是在学习Spring中所熟悉的.
FileSystemXmlApplicationContext 和 ClassPathXmlApplicationContext
两种不同的方式(从文件系统中加载配置和从类路径中加载配置.)
目的都是为了加载bean的配置.
其抽象是 AbstractXmlApplicationContext



