简单 工厂方法 抽象 区别
三个工厂的区别
-
简单:提供方法的工厂。并不算设计模式,
-
我要A对象 ,你给我A对象 ,B对象也是这里要。拿哪一个你帮我选。
-
产品工厂——> 产品接口(if else)——> 产品A,B,C
-
-
工厂方法:提供工厂的方法。
-
工厂里有提供不同对象的方法,你给我1,我给你优惠券的服务,你可直接用。
-
抽象工厂——>产品接口——>工厂实现类(ABC工厂),A工厂 有产品A
-
想用 那个产品,调用哪个工厂
-
-
抽象:提供组合工厂的方法。对 工厂方法的优化。
-
JDKProxyFactory.getProxy(CacheService.class, EGMCacheAdapter.class);
- 我告诉你用什么逻辑,使用什么实现,我创建代理对象给你
-
抽象工厂——产品接口——工厂X——里面有产品A和B (同类产品,交给一个工厂)
- 工厂C——有产品C
-
-
一个窗口:刀削面,手擀面,油泼面 (交给里面的人,服务员 帮我选)
-
三个窗口:分开
-
组合窗口:清真(兰州拉面),普通(麻辣烫)
抽象工厂:
解释:围绕 一个超级工厂 创建其他工厂。
-
该 超级工厂 又称为 其他工厂的工厂。
- 这种类型的设计模式 属于创建型 模式,
- 它提供了一种 创建对象的最佳方式。
-
球形工厂
-
金字塔形工厂
场景:替换Redis双集群升级,代理类 抽象场景。
1. 工厂方法模式
1.1 基本定义
和 策略,适配器,模板方法 像
又称 工厂模式,
- 是 一种 创建型 设计模式
- 其 在 父类中 提供一个 创建对象的方法,
- 允许 子类决定 实例化 对象的 类型
多种类型 商品不同接口,统一发奖 服务搭建场景
物流
- 陆上
- 海上
商店,定义成工厂 ===> 奖品接口
- 兑换卡
- 事物商品
- 优惠券
1.2 基本的实体 和 实现
爱奇艺
public class IQiYiCard {
}
public class IQiYiCardService {
public void grantToken(String bindMobileNumber, String cardId) {
System.out.println("模拟发放爱奇艺会员卡一张:" + bindMobileNumber + "," + cardId);
}
}
优惠券
//优惠券
public class CouponInfo {
}
public class CouponResult {
private String code; // 编码
private String info; // 描述
}
public class CouponService {
public CouponResult sendCoupon(String uId, String couponNumber, String uuid) {
System.out.println("模拟发放优惠券一张:" + uId + "," + couponNumber + "," + uuid);
return new CouponResult("0000", "发放成功");
}
}
实物类
// 实物
public class GoodsInfo {
}
public class DeliverReq {
private String userName; // 用户姓名
private String userPhone; // 用户手机
private String sku; // 商品SKU
private String orderId; // 订单ID
private String consigneeUserName; // 收货人姓名
private String consigneeUserPhone; // 收货人手机
private String consigneeUserAddress; // 收获人地址
}
public class GoodsService {
public Boolean deliverGoods(DeliverReq req) {
System.out.println("模拟发货实物商品一个:" + JSON.toJSONString(req));
return true;
}
}
xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>cn.bugstack.design</groupId>
<artifactId>tutorials-4.0-1</artifactId>
<version>1.0-SNAPSHOT</version>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
<!-- https://mvnrepository.com/artifact/com.alibaba/fastjson -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.62</version>
</dependency>
<!-- LOGGING begin -->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.7.5</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>jcl-over-slf4j</artifactId>
<version>1.7.5</version>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>1.0.9</version>
<exclusions>
<exclusion>
<artifactId>slf4j-api</artifactId>
<groupId>org.slf4j</groupId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>cn.bugstack.design</groupId>
<artifactId>tutorials-4.0-0</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>8</source>
<target>8</target>
</configuration>
</plugin>
</plugins>
</build>
</project>
发奖的请求 或 返回
public class AwardReq {
private String uId; // 用户唯一ID
private Integer awardType; // 奖品类型(可以用枚举定义);1优惠券、2实物商品、3第三方兑换卡(爱奇艺)
private String awardNumber; // 奖品编号;sku、couponNumber、cardId
private String bizId; // 业务ID,防重复
private Map<String, String> extMap; // 扩展信息
}
public class AwardRes {
private String code; // 编码
private String info; // 描述
}
1.3 不使用设计模式
public class PrizeController {
private Logger logger = LoggerFactory.getLogger(PrizeController.class);
public AwardRes awardToUser(AwardReq req) {
//返回的对象
AwardRes awardRes = null;
//请求对象转为json
String reqJson = JSON.toJSONString(req);
try {
logger.info("奖品发放开始{}。req:{}", req.getuId(), reqJson);
// 按照不同类型方法商品[1优惠券、2实物商品、3第三方兑换卡(爱奇艺)]
if (req.getAwardType() == 1) {
//优惠券service
CouponService couponService = new CouponService();
//调用具体的逻辑
CouponResult couponResult = couponService.sendCoupon(req.getuId(), req.getAwardNumber(), req.getBizId());
if ("0000".equals(couponResult.getCode())) {
awardRes = new AwardRes("0000", "发放成功");
} else {
awardRes = new AwardRes("0001", couponResult.getInfo());
}
} else if (req.getAwardType() == 2) {
//实物的service
GoodsService goodsService = new GoodsService();
//创建 实物对象
DeliverReq deliverReq = new DeliverReq();
deliverReq.setUserName(queryUserName(req.getuId()));
deliverReq.setUserPhone(queryUserPhoneNumber(req.getuId()));
deliverReq.setSku(req.getAwardNumber());
deliverReq.setOrderId(req.getBizId());
deliverReq.setConsigneeUserName(req.getExtMap().get("consigneeUserName"));
deliverReq.setConsigneeUserPhone(req.getExtMap().get("consigneeUserPhone"));
deliverReq.setConsigneeUserAddress(req.getExtMap().get("consigneeUserAddress"));
//发放
Boolean isSuccess = goodsService.deliverGoods(deliverReq);
if (isSuccess) {
awardRes = new AwardRes("0000", "发放成功");
} else {
awardRes = new AwardRes("0001", "发放失败");
}
} else if (req.getAwardType() == 3) {
//获取 用户编号
String bindMobileNumber = queryUserPhoneNumber(req.getuId());
//创建 爱奇艺service
IQiYiCardService iQiYiCardService = new IQiYiCardService();
iQiYiCardService.grantToken(bindMobileNumber, req.getAwardNumber());
awardRes = new AwardRes("0000", "发放成功");
}
logger.info("奖品发放完成{}。", req.getuId());
} catch (Exception e) {
logger.error("奖品发放失败{}。req:{}", req.getuId(), reqJson, e);
awardRes = new AwardRes("0001", e.getMessage());
}
return awardRes;
}
private String queryUserName(String uId) {
return "花花";
}
private String queryUserPhoneNumber(String uId) {
return "15200101232";
}
}
1.4 使用设计模式
发放商品的接口
commodity
英 /kəˈmɒdəti/ 美 /kəˈmɑːdəti/ 全球(美国)
简明 牛津 新牛津 韦氏 柯林斯 例句 百科
n. 商品,货物;有用的东西,必需品
public interface ICommodity {
//用户ID ,奖品ID,业务ID,
void sendCommodity(String uId, String commodityId, String bizId, Map<String, String> extMap) throws Exception;
}
爱奇艺卡实现
public class CardCommodityService implements ICommodity {
private Logger logger = LoggerFactory.getLogger(CardCommodityService.class);
// 模拟注入
private IQiYiCardService iQiYiCardService = new IQiYiCardService();
public void sendCommodity(String uId, String commodityId, String bizId, Map<String, String> extMap) throws Exception {
String mobile = queryUserMobile(uId);
iQiYiCardService.grantToken(mobile, bizId);
logger.info("请求参数[爱奇艺兑换卡] => uId:{} commodityId:{} bizId:{} extMap:{}", uId, commodityId, bizId, JSON.toJSON(extMap));
logger.info("测试结果[爱奇艺兑换卡]:success");
}
private String queryUserMobile(String uId) {
return "15200101232";
}
}
优惠券的实现
public class CouponCommodityService implements ICommodity {
private Logger logger = LoggerFactory.getLogger(CouponCommodityService.class);
private CouponService couponService = new CouponService();
public void sendCommodity(String uId, String commodityId, String bizId, Map<String, String> extMap) throws Exception {
CouponResult couponResult = couponService.sendCoupon(uId, commodityId, bizId);
logger.info("请求参数[优惠券] => uId:{} commodityId:{} bizId:{} extMap:{}", uId, commodityId, bizId, JSON.toJSON(extMap));
logger.info("测试结果[优惠券]:{}", JSON.toJSON(couponResult));
if (!"0000".equals(couponResult.getCode())) throw new RuntimeException(couponResult.getInfo());
}
}
实物商品实现
public class GoodsCommodityService implements ICommodity {
private Logger logger = LoggerFactory.getLogger(GoodsCommodityService.class);
private GoodsService goodsService = new GoodsService();
public void sendCommodity(String uId, String commodityId, String bizId, Map<String, String> extMap) throws Exception {
DeliverReq deliverReq = new DeliverReq();
deliverReq.setUserName(queryUserName(uId));
deliverReq.setUserPhone(queryUserPhoneNumber(uId));
deliverReq.setSku(commodityId);
deliverReq.setOrderId(bizId);
deliverReq.setConsigneeUserName(extMap.get("consigneeUserName"));
deliverReq.setConsigneeUserPhone(extMap.get("consigneeUserPhone"));
deliverReq.setConsigneeUserAddress(extMap.get("consigneeUserAddress"));
Boolean isSuccess = goodsService.deliverGoods(deliverReq);
logger.info("请求参数[实物商品] => uId:{} commodityId:{} bizId:{} extMap:{}", uId, commodityId, bizId, JSON.toJSON(extMap));
logger.info("测试结果[实物商品]:{}", isSuccess);
if (!isSuccess) throw new RuntimeException("实物商品发放失败");
}
private String queryUserName(String uId) {
return "花花";
}
private String queryUserPhoneNumber(String uId) {
return "15200101232";
}
}
具体的工厂
public class StoreFactory {
/**
* 奖品类型方式实例化
* @param commodityType 奖品类型
* @return 实例化对象
*/
public ICommodity getCommodityService(Integer commodityType) {
if (null == commodityType) return null;
if (1 == commodityType) return new CouponCommodityService();
if (2 == commodityType) return new GoodsCommodityService();
if (3 == commodityType) return new CardCommodityService();
throw new RuntimeException("不存在的奖品服务类型");
}
/**
* 奖品类信息方式实例化
* @param clazz 奖品类。如:CouponCommodityService.class,创建具体的 service
* @return 实例化对象
*/
public ICommodity getCommodityService(Class<? extends ICommodity> clazz) throws IllegalAccessException, InstantiationException {
if (null == clazz) return null;
return clazz.newInstance();
}
}
进行测试
public class ApiTest {
@Test
public void test_StoreFactory_01() throws Exception {
StoreFactory storeFactory = new StoreFactory();
// 1. 优惠券
ICommodity commodityService_1 = storeFactory.getCommodityService(1);
commodityService_1.sendCommodity("10001", "EGM1023938910232121323432", "791098764902132", null);
// 2. 实物商品
ICommodity commodityService_2 = storeFactory.getCommodityService(2);
commodityService_2.sendCommodity("10001", "9820198721311", "1023000020112221113", new HashMap<String, String>() {{
put("consigneeUserName", "谢飞机");
put("consigneeUserPhone", "15200292123");
put("consigneeUserAddress", "吉林省.长春市.双阳区.XX街道.檀溪苑小区.#18-2109");
}});
// 3. 第三方兑换卡(模拟爱奇艺)
ICommodity commodityService_3 = storeFactory.getCommodityService(3);
commodityService_3.sendCommodity("10001", "AQY1xjkUodl8LO975GdfrYUio", null, null);
}
@Test
public void test_StoreFactory_02() throws Exception {
StoreFactory storeFactory = new StoreFactory();
// 1. 优惠券
ICommodity commodityService = storeFactory.getCommodityService(CouponCommodityService.class);
commodityService.sendCommodity("10001", "EGM1023938910232121323432", "791098764902132", null);
}
}
2. 抽象工厂
2.2 redis基本类
基本接口和实现
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);
}
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);
}
}
单机的redis的工具类
public class RedisUtils {
private Logger logger = LoggerFactory.getLogger(RedisUtils.class);
private Map<String, String> 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);
}
}
Redis集群,EGM 和 IIR
- 大概是 服务器的名字
/**
* 模拟Redis缓存服务,EGM
*/
public class EGM {
private Logger logger = LoggerFactory.getLogger(EGM.class);
private Map<String, String> dataMap = new ConcurrentHashMap<String, String>();
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);
}
}
/**
* 模拟Redis缓存服务,IIR
*/
public class IIR {
private Logger logger = LoggerFactory.getLogger(IIR.class);
......
}
2.3 不使用模式
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);
}
/**
* 升级后,使用多套Redis集群服务,同时兼容以前单体Redis服务
*/
public class CacheClusterServiceImpl 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);
return;
}
redisUtils.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);
return;
}
if (2 == redisType) {
iir.setExpire(key, value, timeout, timeUnit);
return;
}
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);
}
}
@Test
public void test_CacheServiceAfterImpl() {
CacheService cacheService = new CacheClusterServiceImpl();
cacheService.set("user_name_01", "小傅哥", 1);
String val01 = cacheService.get("user_name_01", 1);
logger.info("缓存集群升级,测试结果:{}", val01);
}
2.4 使用模式
车间适配器 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);
}
IIR 和 EGM实现
public class IIRCacheAdapter implements ICacheAdapter {
private IIR iir = new IIR();
@Override
public String get(String key) {
return iir.get(key);
}
@Override
public void set(String key, String value) {
iir.set(key, value);
}
@Override
public void set(String key, String value, long timeout, TimeUnit timeUnit) {
iir.setExpire(key, value, timeout, timeUnit);
}
@Override
public void del(String key) {
iir.del(key);
}
}
public class EGMCacheAdapter implements ICacheAdapter {
private EGM egm = new EGM();
......
public void set(String key, String value, long timeout, TimeUnit timeUnit) {
egm.setEx(key, value, timeout, timeUnit); //这里不同
}
}
classLoaderUtils 通用的
//类 加载器工具
public class ClassLoaderUtils {
//根据 Object数组,返回对应的 class数据
public static Class<?>[] getClazzByArgs(Object[] args) {
//创建一个 类文件 数组
Class<?>[] parameterTypes = new Class[args.length];
//遍历参数的数组
for (int i = 0; i < args.length; i++) {
//如果是 ArrayList,就把 List赋值
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;
}
}
JDK 工厂 和 InvocationHandler
invocation
英 /ˌɪnvəˈkeɪʃn/ 美 /ˌɪnvəˈkeɪʃn/ 全球(美国)
n. (向神或权威人士的)求助,祈祷;咒语;(仪式或集会开始时的)发言,祷文;(法院对另案的)文件调取;(计算机)调用,启用;(法权的)行使
handler
英 /ˈhændlə(r)/ 美 /ˈhændlər/ 全球(美国)
n. 处理者;管理者;拳击教练;(犬马等的)训练者
n. (Handler)人名;(法)昂德莱;(英)汉德勒
public class JDKInvocationHandler implements InvocationHandler {
//定义 适配器
private ICacheAdapter cacheAdapter;
//构造注入
public JDKInvocationHandler(ICacheAdapter cacheAdapter) {
this.cacheAdapter = cacheAdapter;
}
//获得 对象,
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//类文件 获得方法(方法名,参数的类文件).invoke(适配器,args);
return ICacheAdapter.class.getMethod(method.getName(),
ClassLoaderUtils.getClazzByArgs(args))
.invoke(cacheAdapter, args);
}
}
public class JDKProxyFactory {
public static <T> T getProxy(Class<T> cacheClazz, Class<? extends ICacheAdapter> cacheAdapter) throws Exception {
//得到 handler
InvocationHandler handler = new JDKInvocationHandler(cacheAdapter.newInstance());
//得到 classLoader
ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
//返回 代理对象
return (T) Proxy.newProxyInstance(classLoader, new Class[]{cacheClazz}, handler);
}
}
测试
public class ApiTest {
private Logger logger = LoggerFactory.getLogger(ApiTest.class);
@Test
public void test_CacheService() throws Exception {
CacheService proxy_EGM = JDKProxyFactory.getProxy(CacheService.class, EGMCacheAdapter.class);
proxy_EGM.set("user_name_01", "小傅哥");
String val01 = proxy_EGM.get("user_name_01");
logger.info("缓存服务 EGM 测试,proxy_EGM.get 测试结果:{}", val01);
CacheService proxy_IIR = JDKProxyFactory.getProxy(CacheService.class, IIRCacheAdapter.class);
proxy_IIR.set("user_name_01", "小傅哥");
String val02 = proxy_IIR.get("user_name_01");
logger.info("缓存服务 IIR 测试,proxy_IIR.get 测试结果:{}", val02);
}
}
EGM写入数据 key:user_name_01 val:小傅哥
EGM获取数据 key:user_name_01
缓存服务 EGM 测试,proxy_EGM.get 测试结果:小傅哥