文章目录
依赖倒置原则
定义:
程序要依赖于抽象接口, 不要依赖于具体实现, 对抽象进行编程, 而不是对实现进行编程, 降低了客户与实现模块的耦合.
高层模块不应该依赖底层模块, 都应该依赖抽象(接口 抽象类)
上级找下级, 一般不会直接找你 ,而是通过助理等找到.
下级去依赖上级的标准等. 上级出的标准, 不需要去关心下级如何去实现的. 降低上级的耦合性.
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));
}
}
控制台打印如下
案例中两种方式的类图
未使用依赖倒置时, 抽奖控制类直接实现两种不同的抽奖方法
使用依赖倒置, 抽奖控制类只需传递抽奖控制的接口, 无需知道底层实现.