0
点赞
收藏
分享

微信扫一扫

设计模式 依赖倒置原则

小磊z 2022-03-13 阅读 40

文章目录

依赖倒置原则

定义:
程序要依赖于抽象接口, 不要依赖于具体实现, 对抽象进行编程, 而不是对实现进行编程, 降低了客户与实现模块的耦合.
高层模块不应该依赖底层模块, 都应该依赖抽象(接口 抽象类)

上级找下级, 一般不会直接找你 ,而是通过助理等找到.
下级去依赖上级的标准等. 上级出的标准, 不需要去关心下级如何去实现的. 降低上级的耦合性.
spring的spi机制等.

依赖倒置原则实战

随机抽奖与权重抽奖.
不使用依赖倒置原则的写法 :
定义抽奖用户类

public class BetUser {

    private String userName;
    // 权重
    private int userWeight;

    public BetUser() {
    }

    public BetUser(String userName, int userWeight) {
        this.userName = userName;
        this.userWeight = userWeight;
    }

    public String getUserName() {
        return userName;
    }

    public void setUserName(String userName) {
        this.userName = userName;
    }

    public int getUserWeight() {
        return userWeight;
    }

    public void setUserWeight(int userWeight) {
        this.userWeight = userWeight;
    }
}

抽奖控制类, 在抽奖控制类中, 分别实现了随机抽奖, 和根据权重排序抽奖的方法.

public class DrawControl {
    
    /**
     // 随机抽奖
     * @param list  抽奖的人集合
     * @param count 中奖人数
     * @return
     */
    public List<BetUser> doDrawRandom(List<BetUser> list, int count) {
        if (list.size() <= count) {
            return list;
        }
        // 集合乱序
        Collections.shuffle(list);

        // 取出指定数量的中奖用户
        List<BetUser> prizeList = new ArrayList<BetUser>();
        for (int i = 0; i < count; i++) {
            prizeList.add(list.get(i));
        }
        return prizeList;
    }
    /**
     *     按权重抽奖
     * @param list
     * @param count
     * @return
     */
    public List<BetUser> doDrawWeight(List<BetUser> list, int count) {
        //按权重排序
        list.sort((o1, o2) -> {
            int e = o2.getUserWeight() - o1.getUserWeight();
            if (e == 0) {
                return 0;
            }
            return e > 0 ? 1 : -1;
        });
        // 取出指定数量的中奖用户
        List<BetUser> prizeList = new ArrayList<>(count);
        for (int i = 0; i < count; i++) {
            prizeList.add(list.get(i));
        }
        return prizeList;
    }
}

测试类

public class ApiTest {

    private Logger logger = LoggerFactory.getLogger(ApiTest.class);

    @Test
    public void test_DrawControl() {
        List<BetUser> betUserList = new ArrayList<>();
        betUserList.add(new BetUser("花花", 65));
        betUserList.add(new BetUser("豆豆", 43));
        betUserList.add(new BetUser("小白", 72));
        betUserList.add(new BetUser("笨笨", 89));
        betUserList.add(new BetUser("丑蛋", 10));

        DrawControl drawControl = new DrawControl();
        List<BetUser> prizeRandomUserList = drawControl.doDrawRandom(betUserList, 3);
        logger.info("随机抽奖, 中奖用户:{}", JSON.toJSON(prizeRandomUserList));

        List<BetUser> prizeWeightUserList = drawControl.doDrawWeight(betUserList, 3);
        logger.info("权重抽奖, 中奖用户名单:{}", JSON.toJSON(prizeWeightUserList));
    }
}

控制台打印如下 :

使用依赖倒置原则进行改变

抽奖用户类与上面一致, 定义一个抽奖的接口

public interface IDraw {

    /**
     *  获取抽奖用户方法
     * @param list 参与 抽奖的人
     * @param count  中奖人数
     * @return
     */
    List<BetUser> prize(List<BetUser> list, int count);
}

分别创建随机抽奖类和权重抽奖类, 实现抽奖接口

public class DrawRandom implements IDraw{

    @Override
    public List<BetUser> prize(List<BetUser> list, int count) {
        if (list.size() <= count) {
            return list;
        }
        // 集合乱序
        Collections.shuffle(list);

        // 取出指定数量的中奖用户
        List<BetUser> prizeList = new ArrayList<BetUser>();
        for (int i = 0; i < count; i++) {
            prizeList.add(list.get(i));
        }
        return prizeList;
    }
}

public class DrawWeightRank implements IDraw {

    @Override
    public List<BetUser> prize(List<BetUser> list, int count) {
        //按权重排序
        list.sort((o1, o2) -> {
            int e = o2.getUserWeight() - o1.getUserWeight();
            if (e == 0) {
                return 0;
            }
            return e > 0 ? 1 : -1;
        });
        // 取出指定数量的中奖用户
        List<BetUser> prizeList = new ArrayList<>(count);
        for (int i = 0; i < count; i++) {
            prizeList.add(list.get(i));
        }
        return prizeList;
    }
}

创建抽奖控制类, 方法入参含有抽奖的接口

public class DrawControl {

    public List<BetUser> doDraw(IDraw draw, List<BetUser> betUserList, int count) {
        return draw.prize(betUserList, count);
    }
}

测试类. drawControl.doDraw 方法中分别new 随机抽奖和权重抽奖.

public class ApiTest {

    private Logger logger = LoggerFactory.getLogger(ApiTest.class);

    @Test
    public void test_DrawControl() {
        List<BetUser> betUserList = new ArrayList<>();
        betUserList.add(new BetUser("花花", 65));
        betUserList.add(new BetUser("豆豆", 43));
        betUserList.add(new BetUser("小白", 72));
        betUserList.add(new BetUser("笨笨", 89));
        betUserList.add(new BetUser("丑蛋", 10));

        DrawControl drawControl = new DrawControl();
        List<BetUser> prizeRandomUserList = drawControl.doDraw(new DrawRandom(), betUserList, 3);
        logger.info("随机抽奖, 中奖用户名单:{}", JSON.toJSON(prizeRandomUserList));

        List<BetUser> prizeWeightUserList = drawControl.doDraw(new DrawWeightRank(), betUserList, 3);
        logger.info("权重抽奖, 中奖用户名单:{}", JSON.toJSON(prizeWeightUserList));
    }
}

控制台打印如下

案例中两种方式的类图

未使用依赖倒置时, 抽奖控制类直接实现两种不同的抽奖方法

使用依赖倒置, 抽奖控制类只需传递抽奖控制的接口, 无需知道底层实现.
在这里插入图片描述

举报

相关推荐

0 条评论