前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >工厂模式

工厂模式

作者头像
周杰伦本人
发布2022-10-25 16:59:03
2170
发布2022-10-25 16:59:03
举报
文章被收录于专栏:同步文章

简单工厂

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

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

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2020-11-02,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 简单工厂
  • 工厂方法
  • 抽象工厂
相关产品与服务
云数据库 Redis
腾讯云数据库 Redis(TencentDB for Redis)是腾讯云打造的兼容 Redis 协议的缓存和存储服务。丰富的数据结构能帮助您完成不同类型的业务场景开发。支持主从热备,提供自动容灾切换、数据备份、故障迁移、实例监控、在线扩容、数据回档等全套的数据库服务。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档