JAVA【设计模式】依赖倒置原则
一、设计模式的规范
设计模式遵循六⼤原则;单⼀职责( ⼀个类和⽅法只做⼀件事 )、⾥⽒替换( 多态,⼦类可扩展⽗类 )、依赖
倒置( 细节依赖抽象,下层依赖上层 )、接⼝隔离( 建⽴单⼀接⼝ )、迪⽶特原则( 最少知道,降低耦合 )、开闭
原则( 抽象架构,扩展实现 ),会在具体的设计模式章节中,进⾏体现。
二、依赖倒置原则
定义:程序依赖接口,接口定义标准和规范,具体的实现按照场景,而不是使用对象硬编码的方式实现
三、示例
模拟场景:
1、例如:领导有事需要开部门例会,领导是不可能去每个工位,喊各位同事去参加会议。领导只会在工作群里面申明,今天什么时间段开会,各位收到消息后,自行去开会。。。
2:例如:用户抽奖有随机抽奖和权重抽奖两种方式,我们只需要定义出一套抽奖抽象标准。具体的实现,看随机和权重的不同实现。
非依赖倒置原则(硬编码)
投注用户:BetUser
package com.qf.principle.dependenceinverse.tradition;
/**
* @description 投注用户
*/
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;
}
}
抽奖控制,硬编码里面的实现方式:DrawControl
package com.qf.principle.dependenceinverse.tradition;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
/**
* @description 抽奖控制
*/
public class DrawControl {
// 随机抽取指定数量的用户,作为中奖用户
public List<BetUser> doDrawRandom(List<BetUser> list, int count) {
// 集合数量很小直接返回
if (list.size() <= count) return list;
// 乱序集合
Collections.shuffle(list);
// 取出指定数量的中奖用户
List<BetUser> prizeList = new ArrayList<>(count);
for (int i = 0; i < count; i++) {
prizeList.add(list.get(i));
}
return prizeList;
}
// 权重排名获取指定数量的用户,作为中奖用户
public List<BetUser> doDrawWeight(List<BetUser> list, int count) {
// 按照权重排序
list.sort((o1, o2) -> {
int e = o2.getUserWeight() - o1.getUserWeight();
if (0 == e) 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;
}
}
测试:ApiTest
package com.qf.principle.dependenceinverse.tradition;
import com.alibaba.fastjson.JSON;
import org.junit.jupiter.api.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.ArrayList;
import java.util.List;
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));
}
}
依赖倒置原则
投注用户:BetUser
package com.qf.principle.dependenceinverse.design;
/**
* @description 投注用户
*/
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;
}
}
定义接口抽奖:IDraw
package com.qf.principle.dependenceinverse.design;
import java.util.List;
public interface IDraw {
List<BetUser> prize(List<BetUser> list, int count);
}
随机抽奖实现:RandomDraw
package com.qf.principle.dependenceinverse.design;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
public class RandomDraw 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<>(count);
for (int i = 0; i < count; i++) {
prizeList.add(list.get(i));
}
return prizeList;
}
}
权重抽奖实现:WeightDraw
package com.qf.principle.dependenceinverse.design;
import java.util.ArrayList;
import java.util.List;
public class WeightDraw implements IDraw {
// 权重排名获取指定数量的用户,作为中奖用户
@Override
public List<BetUser> prize(List<BetUser> list, int count) {
// 按照权重排序
list.sort((o1, o2) -> {
int e = o2.getUserWeight() - o1.getUserWeight();
if (0 == e) 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;
}
}
抽奖控制:DrawControl
package com.qf.principle.dependenceinverse.design;
import java.util.List;
/**
* @description 抽奖控制
*/
public class DrawControl {
private IDraw draw;
public List<BetUser> doDraw(IDraw draw,List<BetUser> list, int count){
return draw.prize(list,count);
}
}
测试:ApiTest
package com.qf.principle.dependenceinverse.design;
import com.alibaba.fastjson.JSON;
import org.junit.jupiter.api.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.ArrayList;
import java.util.List;
public class ApiTest {
private Logger logger = LoggerFactory.getLogger(com.qf.principle.dependenceinverse.tradition.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 RandomDraw(),betUserList,3);
logger.info("随机抽奖,中奖用户名单:{}", JSON.toJSON(prizeRandomUserList));
List<BetUser> prizeWeightUserList=drawControl.doDraw(new WeightDraw(),betUserList,3);
logger.info("权重抽奖,中奖用户名单:{}", JSON.toJSON(prizeWeightUserList));
}
}
UML关系图
硬编码的方式:具体的实现都在此类里
依赖倒置方式:
总结:
依赖倒置原则增加了代码的可维护性,利用多态的特性,上级只需要定义标准,下级负责实现,跟装饰者模式有点类似