加上 合成复用,这里没讲。
它们是某个外卖骑手,合(着你),一里接单 (还)开(奥)迪?
好吧,是:
依里 接单 开笛,希望你记住了。
- 依赖倒置,依赖倒转:一流公司制定标准,二流…
皇帝想办事,皇帝写好圣旨,别人念,别人告诉皇帝事情办成了。 - 里式代换,里式转换:长江后浪推前浪,后浪的人,前浪的都会
- 接口隔离
- 单一职责
- 开闭原则:两个字太单调,加了原则。
- 迪米特法则:各人自扫门前雪。
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 测试结果:张三