设计模式:7原则 和 工厂方法,抽象工厂 模式极简代码

加上 合成复用,这里没讲。

它们是某个外卖骑手,合(着你),一里接单 (还)开(奥)迪?

好吧,是:

依里 接单 开笛,希望你记住了。

  • 依赖倒置,依赖倒转:一流公司制定标准,二流…
    皇帝想办事,皇帝写好圣旨,别人念,别人告诉皇帝事情办成了。
  • 里式代换,里式转换:长江后浪推前浪,后浪的人,前浪的都会
  • 接口隔离
  • 单一职责
  • 开闭原则:两个字太单调,加了原则。
  • 迪米特法则:各人自扫门前雪。

在这里插入图片描述

1. 单一职责 VIP没广告

  • 各自逻辑,继承各自的实现
public interface VideoUserInter {
    void definition();
}

public class VipVideoUserService implements VideoUserInter {
    @Override
    public void definition() {
        System.out.println("VIP用户,视频1080P蓝光");
    }

    public static void main(String[] args) {
        VideoUserInter v=new VipVideoUserService();
        v.definition();
    }
}

2. 开闭原则 增加精密圆面积

统一的 接口和实现

public interface CalculationAreaInter {

    /**
     * 计算面积,三角形
     * @param x 边长x
     * @param y 边长y
     * @param z 边长z
     * @return  面积
     */
    double triangle(double x, double y, double z);

    /**
     * 计算面积,圆形
     * @param r 半径
     * @return 面积
     *
     * 圆面积公式:S=πr²
     */
    double circular(double r);
}

public class CalculationArea implements CalculationAreaInter {

    private final static double π = 3.14D;

    //海伦公式:S=√[p(p-a)(p-b)(p-c)] 其中:p=(a+b+c)/2
    @Override
    public double triangle(double x, double y, double z) {
        //三边长 / 2 得到 p
        double p = (x + y + z) / 2;
        //用 p 分别 减去 三边长,在乘,在乘 P,在开方
        return Math.sqrt(p * (p - x) * (p - y) * (p - z));
    }

    @Override
    public double circular(double r) {
        return π * r * r;
    }
}

我的扩展,不动原接口

public class CalculationAreaExt extends CalculationArea {
    private final static double π = 3.141592653D;

    @Override
    public double circular(double r) {
        return π * r * r;
    }

    public static void main(String[] args) {
        CalculationAreaInter area = new CalculationAreaExt();
        double circular = area.circular(10);
        System.out.println(circular);
    }
}

3. 里式替换 信用卡有父类的功能

抽象的父类 银行卡

@Slf4j
@Getter
@AllArgsConstructor
public abstract class BankCard {
    private String cardNo;   // 卡号
    private String cardDate; // 开卡时间

    // 正向入账,+ 钱
    public String add(String orderId, BigDecimal amount) {
        log.info("卡号{} 入款成功,单号:{} 金额:{}", cardNo, orderId, amount);
        return "0000";
    }

}

储蓄卡 存钱

@Slf4j
public class CashCard extends BankCard {

    //通过构造,对 父类赋值。
    public CashCard(String cardNo, String cardDate) {
        super(cardNo, cardDate);
    }

    public String recharge(String orderId, BigDecimal amount) {
        // 模拟充值成功
        log.info("储蓄成功,单号:{} 金额:{}", orderId, amount);
        return super.add(orderId, amount);
    }
}

信用卡 还款

@Slf4j
public class CreditCard extends CashCard {

    //构造 传递给 父类
    public CreditCard(String cardNo, String cardDate) {
        super(cardNo, cardDate);
    }

    //还款,加钱
    public String repayment(String orderId, BigDecimal amount) {

        // 模拟还款成功
        log.info("还款成功,单号:{} 金额:{}", orderId, amount);
        return super.add(orderId, amount);
    }

}
    public static void main(String[] args) {

        CreditCard c = new CreditCard("6214567800989876", "2022-03-05");

        //还款,就是存钱
        c.repayment("100001", new BigDecimal(100));

        c.recharge("100002", new BigDecimal(100));

    }
    
    
还款成功,单号:100001 金额:100
卡号6214567800989876 入款成功,单号:100001 金额:100

储蓄成功,单号:100002 金额:100
卡号6214567800989876 入款成功,单号:100002 金额:100

4. 迪米特 校长别管太多

学生 和 老师类

  • 老师类,负责计算
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Student {
    private String name;    // 学生姓名
    private int    rank;       // 考试排名(总排名)
    private double grade;   // 考试分数(总分)
}

@Getter
@AllArgsConstructor
public class Teacher {
    private static List<Student> studentList;  // 学生

    static {
        studentList = new ArrayList<>();
        studentList.add(new Student("花花", 10, 589));
        studentList.add(new Student("蛋蛋", 19, 502));
    }

    private String name;                // 老师名称
    private String clazz;               // 班级

    // 总分
    public double totalScore() {
        double totalScore = 0;
        for (Student stu : studentList) {
            totalScore += stu.getGrade();
        }
        return totalScore;
    }

    // 平均分
    public double averageScore() {
        return totalScore() / studentList.size();
    }

    // 班级人数
    public int studentCount() {
        return studentList.size();
    }
}

校长类 只管老师

  • 使用老师的数据
public class Principal {

    private Teacher t = new Teacher("丽华", "3年1班");

    public static void main(String[] args) {
        //{学生人数=2, 班级平均分=545.5, 班级=3年1班, 老师=丽华, 班级总分数=1091.0}
        System.out.println(new Principal().queryClazzInfo());
    }

    // 查询班级信息,总分数、学生人数、平均值
    public Map<String, Object> queryClazzInfo() {

        Map<String, Object> mapObj = new HashMap<>();
        mapObj.put("班级", t.getClazz());
        mapObj.put("老师", t.getName());
        mapObj.put("学生人数", t.studentCount());
        mapObj.put("班级总分数", t.totalScore());
        mapObj.put("班级平均分", t.averageScore());
        return mapObj;
    }
}

5. 接口隔离 英雄技能为单个接口

  • 抽接口多实现
public interface ISkillArchery {
    // 射箭
    void doArchery();
}

public interface ISkillInvisible {
    // 隐袭
    void doInvisible();
}

后裔英雄

  • 要什么功能,就实现什么接口
public class HeroHouYi implements ISkillArchery, ISkillInvisible {
    public static void main(String[] args) {
        HeroHouYi h = new HeroHouYi();
        h.doArchery();
    }

    @Override
    public void doArchery() {
        System.out.println("后裔的灼日之矢");
    }
    @Override
    public void doInvisible() {
        System.out.println("后裔的隐身技能");
    }
}

6. 依赖倒置 抽奖控制用接口,你传递实现

  • 高低层模块 共同依赖接口

  • 改成:上级指定标准,

  • 下级(依赖于上级说的话)做完后,

  • 交上来(倒置)

基本类

@AllArgsConstructor
@NoArgsConstructor
@Data
public class BetUser {

    private String userName;  // 用户姓名
    private int    userWeight;   // 用户权重
}

public interface IDraw {
    List<BetUser> prize(List<BetUser> list, int count);
}

两种规则的实现

public class DrawRandom implements IDraw {

    @Override
    public List<BetUser> prize(List<BetUser> list, int count) {

        // 乱序集合
        Collections.shuffle(list);

        return list.subList(0, count);
    }

        /*
        //list.stream().limit(count).toList();
        // 集合数量很小直接返回
        if (list.size() <= count) {
            return list;
        }*/
    
        /* 取出指定数量的中奖用户
        List<BetUser> prizeList = new ArrayList<>(count);
        for (int i = 0; i < count; i++) {
            prizeList.add(list.get(i));
        }*/
}



public class DrawWeight implements IDraw {

    @Override
    public List<BetUser> prize(List<BetUser> list, int count) {
        // 按照权重排序

        return list.stream().sorted(Comparator.comparing(BetUser::getUserWeight).reversed())
            .limit(count).toList();
    }
}

       /*list.sort((o1, o2) -> {
            int e = o2.getUserWeight() - o1.getUserWeight();
            if (0 == e) {
                return 0;
            }
            return e > 0 ? 1 : -1;
        });
        // 取出指定数量的中奖用户
        .subList(0, count)
        */

抽奖控制类

public class DrawControl {
    //把接口拿出来,用接口的抽奖
    //private IDraw draw;

    public List<BetUser> doDraw(IDraw draw, List<BetUser> betUserList, int count) {
        return draw.prize(betUserList, count);
    }
}
    public static void main(String[] args) {
        List<BetUser> bList = new ArrayList<>();
        bList.add(new BetUser("花花", 65));
        bList.add(new BetUser("豆豆", 43));
        bList.add(new BetUser("小白", 72));
        bList.add(new BetUser("笨笨", 89));
        bList.add(new BetUser("丑蛋", 10));

        DrawControl d = new DrawControl();

        List<BetUser> list = d.doDraw(new DrawWeight(), bList, 3);

        System.out.println(list);
    }
        /*List<BetUser> list = drawControl.doDraw(new DrawRandom(), betUserList, 3);
        System.out.println(list);*/
[BetUser(userName=笨笨, userWeight=89), BetUser(userName=小白, userWeight=72), BetUser(userName=花花, userWeight=65)]

工厂方法,抽象工厂

1. 工厂方法 工厂创建各种发奖实现对象

统一发奖的顶层接口

public interface provideInter {
    //用户ID ,奖品ID,业务ID,
    void sendCommodity(String uId, String commodityId,
                       String bizId,
                       Map<String, String> extMap) throws Exception;
}

优惠券和实物的实现

@Slf4j
public class CouponService implements provideInter {

    @Override
    public void sendCommodity(String uId, String commodityId, String bizId, Map<String, String> extMap) throws Exception {

        CouponResult couponResult = sendCoupon(uId, commodityId, bizId);

        if (!"0000".equals(couponResult.getCode())) {
            throw new RuntimeException(couponResult.getInfo());
        }
    }

    public CouponResult sendCoupon(String uId, String couponNumber, String uuid) {
        System.out.println("模拟发放优惠券一张:" + uId + "," + couponNumber + "," + uuid);
        return new CouponResult("0000", "发放成功");
    }

    @Data
    @AllArgsConstructor
    public class CouponResult {

        private String code; // 编码
        private String info; // 描述
    }
}



@Slf4j
public class GoodsService implements provideInter {

    @Override
    public void sendCommodity(String uId, String commodityId, String bizId, Map<String, String> extMap) throws Exception {
        DeliverReq deliverReq = new DeliverReq();
        deliverReq.setUserName("UserName"+uId);
        deliverReq.setUserPhone("UserPhoneNumber"+uId);
        deliverReq.setSku(commodityId);
        deliverReq.setOrderId(bizId);
        deliverReq.setConsigneeUserName(extMap.get("consigneeUserName"));
        deliverReq.setConsigneeUserPhone(extMap.get("consigneeUserPhone"));
        deliverReq.setConsigneeUserAddress(extMap.get("consigneeUserAddress"));

        Boolean isSuccess = deliverGoods(deliverReq);

        if (!isSuccess) {
            throw new RuntimeException("实物商品发放失败");
        }
    }

    public Boolean deliverGoods(DeliverReq req) {
        System.out.println("模拟发货实物商品一个:" + req);
        return true;
    }


    @Data
    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 StoreFactory {

    /**
     * 奖品类型方式实例化
     *
     * @param commodityType 奖品类型
     * @return 实例化对象
     */
    public provideInter getCommodityService(Integer commodityType) {
        if (null == commodityType) {
            return null;
        }
        if (1 == commodityType) {
            return new CouponService();
        }
        if (2 == commodityType) {
            return new GoodsService();
        }
        throw new RuntimeException("不存在的奖品服务类型");
    }

    /**
     * 奖品类信息方式实例化
     *
     * @param clazz 奖品类。如:CouponCommodityService.class,创建具体的 service
     * @return 实例化对象
     */
    public provideInter getCommodityService(Class<? extends provideInter> clazz) throws IllegalAccessException, InstantiationException {
        if (null == clazz) {
            return null;
        }
        //有了 class,使用此方法即可。clazz.getDeclaredConstructor().newInstance() 使用这个
        return clazz.newInstance();//已经废弃
    }

}

进行测试

        //这是一个 工厂,工厂提供了,创建 所有的类
		StoreFactory storeFactory = new StoreFactory();

        // 1. 优惠券
        provideInter p1 = storeFactory.getCommodityService(1);
        p1.sendCommodity("10001", "EGM1023938910232121323432", "791098764902132", null);

        // 2. 实物商品
        provideInter p2 = storeFactory.getCommodityService(2);
        p2.sendCommodity("10001", "9820198721311", "1023000020112221113", new HashMap<String, String>() {{
            put("consigneeUserName", "谢飞机");
            put("consigneeUserPhone", "15200292123");
            put("consigneeUserAddress", "吉林省.长春市.双阳区.XX街道.檀溪苑小区.#18-2109");
        }});

		//另一种方式,传递 具体的实现类的 class即可。
        // 1. 优惠券
        provideInter commodityService = storeFactory.getCommodityService(CouponService.class);
        commodityService.sendCommodity("10001", "EGM1023938910232121323432", "791098764902132", null);
模拟发放优惠券一张:10001,EGM1023938910232121323432,791098764902132

模拟发货实物商品一个:
GoodsService.DeliverReq
(
userName=UserName10001, 
userPhone=UserPhoneNumber10001, 
sku=9820198721311, 
orderId=1023000020112221113, 
consigneeUserName=谢飞机, 
consigneeUserPhone=15200292123, 
consigneeUserAddress=吉林省.长春市.双阳区.XX街道.檀溪苑小区.#18-2109
)

2. 抽象工厂 给我redis实现,我就代理谁

  • 就是代理一个接口,真实代理的是 接口的实现。
  • 使用的时候,用任意一个接口相同
    • 并且接口的方法相同
    • 的接口,接收都行。本接口也行。

一个接口 和 实现

//车间适配器
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);
}


@Slf4j
public class IIRCacheAdapter implements ICacheAdapter {
    
    private Map<String, String> dataMap = new ConcurrentHashMap<String, String>();

    @Override
    public String get(String key) {
        log.info("IIR获取数据 key:{}", key);
        return dataMap.get(key);
    }

    @Override
    public void set(String key, String value) {
        log.info("IIR写入数据 key:{} val:{}", key, value);
        dataMap.put(key, value);
    }

    @Override
    public void set(String key, String value, long timeout, TimeUnit timeUnit) {
        log.info("IIR写入数据 key:{} val:{} timeout:{} timeUnit:{}", key, value, timeout, timeUnit.toString());
        dataMap.put(key, value);
    }

    @Override
    public void del(String key) {
        log.info("IIR删除数据 key:{}", key);
        dataMap.remove(key);
    }
}

对接口进行代理

InvocationHandler
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);
    }
}
代理工厂类
@Slf4j
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);
    }

}
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;
    }
}
随便一个同样的接口
  • 保证接口和参数一样
  • 不一样的话,不能调用
public interface TempInterface {

    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 static void main(String[] args) throws Exception {
        //使用 临时的接口 也可以。
        TempInterface p = JDKProxyFactory.getProxy(TempInterface.class, IIRCacheAdapter.class);

        //使用 自己代理的接口 也可以。
		//ICacheAdapter p = JDKProxyFactory.getProxy(ICacheAdapter.class, IIRCacheAdapter.class);

        p.set("user_name_01", "张三");

        String v = p.get("user_name_01");

        log.info("缓存服务 EGM 测试,get 测试结果:{}", v);

    }
IIR写入数据 key:user_name_01 val:张三
IIR获取数据 key:user_name_01

缓存服务 EGM 测试,get 测试结果:张三
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值