工厂模式

2022-10-25 16:59:03 浏览数 (2)

简单工厂

简单工厂其实很简单 把逻辑写在了工厂类中

代码语言: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

0 人点赞