简单工厂
简单工厂其实很简单 把逻辑写在了工厂类中
代码语言:javascript复制public class OperationFactory {
public static Operation createOperation(char opreator) {
Operation operation = null;
switch (opreator) {
case ' ':
operation = new OperationAdd();
break;
case '-':
operation = new OperationSub();
break;
case '*':
operation = new OperationMul();
break;
case '/':
operation = new OperationDiv();
break;
default:
throw new RuntimeException("unsupported operation");
}
return operation;
}
}
代码语言:javascript复制public abstract class Operation {
public double numberA;
public double numberB;
public abstract double result();
}
代码语言:javascript复制public class OperationAdd extends Operation {
@Override
public double result() {
return numberA numberB;
}
}
代码语言:javascript复制public class OperationSub extends Operation {
public double result() {
return numberA - numberB;
}
}
代码语言:javascript复制public class OperationMul extends Operation {
public double result() {
return numberA * numberB;
}
}
代码语言:javascript复制public class OperationDiv extends Operation {
public double result() {
if (numberB == 0) {
throw new RuntimeException("divided by 0");
}
return numberA/numberB;
}
}
代码语言:javascript复制public class Calculator {
public static void main(String[] args) {
Operation operation;
char operator;
operator = ' ';
operation = OperationFactory.createOperation(operator);
operation.numberA = 1.2;
operation.numberB = 2.3;
System.out.println(operation.result());
}
}
工厂方法
简单工厂模式的最大优点在于工厂类中包含了必要的逻辑判断,根据客户端的选择条件动态实例化相关的类,对于客户端来说,去除了与具体产品的依赖。就像你的计算器,让客户端不用管该用哪个类的实例,只需要把‘ ’ 给工厂,工厂自动就给出了相应的实例,客户端只要去做运算就可以了,不同的实例会实现不同的运算。但问题也就在这里,如你所说,如果要加一个‘求M数的N次方’的功能,我们是一定需要给运算工厂类的方法里加’Case’的分支条件的,修改原有的类?这可不是好办法,这就等于说,我们不但对扩展开放了,对修改也开放了,这样就违背的是开放-封闭原则。 工厂方法模式(Factory Method),定义-一个用于创建对象的接口,让子类决定实例化哪一个类。工厂方法使-一个类的实例化延迟到其子类。
既然这个工厂类与分支耦合,那么我就对它下手,根据依赖倒转原则,我们把工厂类抽象出一一个接口,这个接口只有一一个方法,就是创建抽象产品的工厂方法。然后,所有的要生产具体类的工厂,就去实现这个接口,这样,一个简单工厂模式的工厂类,变成了一个工厂抽象接口和多个具体生成对象的工厂,于是我们要增加‘求M数的N次方’的功能时,就不需要更改原有的工厂类了,只需要增加此功能的运算类和相应的工厂类就可以了。
)
工厂方法模式实现时,客户端需要决定实例化哪- -个工厂来实现运算类,选择判断的问题还是存在的,也就是说,工厂方法把简单工厂的内部逻辑判断移到了客户端代码来进行。你想要加功能,本来是改工厂类的,而现在是修改客户端!
代码语言:javascript复制public interface IFactory {
public Operation createOperation();
}
代码语言:javascript复制public class AddFactory implements IFactory {
public Operation createOperation() {
return new OperationAdd();
}
}
代码语言:javascript复制public class SubFactory implements IFactory {
public Operation createOperation() {
return new OperationSub();
}
}
代码语言:javascript复制public class MulFactory implements IFactory {
public Operation createOperation() {
return new OperationMul();
}
}
代码语言:javascript复制public class DivFactory implements IFactory {
public Operation createOperation() {
return new OperationDiv();
}
}
代码语言:javascript复制public class FactoryClient {
public static void main(String[] args) {
char operator;
operator = ' ';
IFactory operaionFactory = null;
switch (operator) {
case ' ':
operaionFactory = new AddFactory();
break;
case '-':
operaionFactory = new SubFactory();
break;
case '*':
operaionFactory = new MulFactory();
break;
case '/':
operaionFactory = new DivFactory();
break;
default:
throw new RuntimeException("unsupported operation");
}
Operation operation = operaionFactory.createOperation();
operation.numberA = 3.4;
operation.numberB = 4.5;
System.out.println(operation.result());
}
}
抽象工厂
抽象工厂模式(Abstract Factory), 提供一-个创建一 系列相关或相互依赖对象的接口,而无需指定它们具体的类。[DP]
反射技术来去除switch 或if,解除分支判断带来的耦合。
代码语言:javascript复制import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy;
/**
* 抽象工厂
*/
public class JDkProxy {
public static <T> T getProxy( Class<T> interfaceClass,ICacheAdpter cacheAdpter) {
InvocationHandler handler = new JDKInvocationHandler(cacheAdpter);
ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
Class<?>[] classes = interfaceClass.getInterfaces();
return (T) Proxy.newProxyInstance(classLoader,new Class[]{classes[0]},handler);
}
}
代码语言:javascript复制import com.xiepanpan.util.CLassLoaderUtils;
import lombok.AllArgsConstructor;
import lombok.NoArgsConstructor;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
/**
* 工厂实现
*/
@AllArgsConstructor
@NoArgsConstructor
public class JDKInvocationHandler implements InvocationHandler {
private ICacheAdpter cacheAdpter;
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//利用反射返回数据
return ICacheAdpter.class.getMethod(method.getName(), CLassLoaderUtils.getClassByArgs(args)).invoke(cacheAdpter,args);
}
}
代码语言:javascript复制/**
* 缓存抽象适配接口
*/
public interface ICacheAdpter {
String get(String key);
void set(String key,String value);
}
代码语言:javascript复制/**
*两个集群中差异化的接口名称
*/
public class ACacheAdapter implements ICacheAdpter {
private ACache aCache = new ACache();
public String get(String key) {
return aCache.gain(key);
}
public void set(String key, String value) {
aCache.set(key,value);
}
}
代码语言:javascript复制import lombok.extern.slf4j.Slf4j;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
/**
* A缓存 A缓存和B缓存提供的接口方法不一样
*/
@Slf4j
public class ACache {
private Map<String,String> dataMap = new ConcurrentHashMap<String, String>();
public String gain(String key) {
log.info("Acache获取数据key:{}",key);
return dataMap.get(key);
}
public void set(String key,String value) {
log.info("Acache写入数据 keyh:{}, value:{}",key,value);
dataMap.put(key,value);
}
}
代码语言:javascript复制import com.xiepanpan.factory.ICacheAdpter;
/**
* 两个集群中差异化的接口名称
*/
public class BCacheAdapter implements ICacheAdpter {
private BCache bCache = new BCache();
public String get(String key) {
return bCache.get(key);
}
public void set(String key, String value) {
bCache.set(key,value);
}
}
代码语言:javascript复制import lombok.extern.slf4j.Slf4j;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
@Slf4j
public class BCache {
private Map<String,String> dataMap = new ConcurrentHashMap<String, String>();
public String get(String key) {
log.info("BCache 获取数据 key:{}",key);
return dataMap.get(key);
}
public void set(String key,String value) {
log.info("BCache 写入数据 Key:{} value: {}",key,value);
dataMap.put(key,value);
}
}
代码语言:javascript复制public interface CacheService {
String get(final String key);
void set(String key,String value);
}
代码语言:javascript复制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);
}
}
两个工具类:
代码语言:javascript复制/**
* 类加载工具类
*/
public class CLassLoaderUtils {
public static Class<?>[] getClassByArgs(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;
}
}
代码语言:javascript复制import lombok.extern.slf4j.Slf4j;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
@Slf4j
public class RedisUtils {
private Map<String,String> dataMap = new ConcurrentHashMap<String, String>();
public String get(String key) {
log.info("Redis获取数据 key:{}",key);
return dataMap.get(key);
}
public void set(String key,String value) {
log.info("Redis写入数据 key:{},value:{}",key,value);
dataMap.put(key,value);
}
}
客户端:
代码语言:javascript复制@Slf4j
public class ApiTest {
@Test
public void testCacheService() {
//在测试的代码中通过传入不同的集群类型,就可以调用不同的集群下的方法。
CacheService proxyAcache = JDkProxy.getProxy(CacheServiceImpl.class, new ACacheAdapter());
proxyAcache.set("username","xiepanpan");
String username = proxyAcache.get("username");
log.info("测试结果:{}",username);
CacheService proxyBcache = JDkProxy.getProxy(CacheServiceImpl.class, new BCacheAdapter());
proxyBcache.set("password","123456");
log.info("密码为: {}",proxyBcache.get("password"));
}
}
效果:
代码语言:javascript复制23:19:46.823 [main] INFO com.xiepanpan.factory.impl.ACache - Acache写入数据 keyh:username, value:xiepanpan
23:19:46.830 [main] INFO com.xiepanpan.factory.impl.ACache - Acache获取数据key:username
23:19:46.830 [main] INFO com.xiepanpan.ApiTest - 测试结果:xiepanpan
23:19:46.831 [main] INFO com.xiepanpan.factory.impl.BCache - BCache 写入数据 Key:password value: 123456
23:19:46.831 [main] INFO com.xiepanpan.factory.impl.BCache - BCache 获取数据 key:password
23:19:46.831 [main] INFO com.xiepanpan.ApiTest - 密码为: 123456
参考文章: 《大话设计模式》
https://bugstack.blog.csdn.net/article/details/106313270