工厂方法模式实战之某商场一次促销活动

目录

      • 1.5.1、前言
      • 1.5.2、实战场景简介
      • 1.5.3、开发环境
      • 1.5.4、用传统的if-else语句实现
        • 1.5.4.1、工程结构
        • 1.5.4.2、if-else需求实现
        • 1.5.4.3、测试验证
      • 1.5.5、工厂模式优化代码
        • 1.5.5.1、工程结构
        • 1.5.5.2、代码实现
          • 1.5.5.2.1、定义各种商品发放接口及接口实现
          • 1.5.5.2.2、定义工厂及统一的发放接口及接口实现
        • 1.5.5.3、测试验证
      • 1.5.6、总结

1.5.1、前言

        本文接上一篇设计模式之工厂方法模式(Factory Method Pattern)介绍工厂方法模式的原理之后接着以一个具体的应用场景(营销场景业务)如何编码实现工厂方法模式。
        为了可以让整个学习的案例更加贴近实际开发,这⾥模拟互联⽹中在营销场景下的业务。由于营销场景的复杂、多变、临时的特性,它所需要的设计需要更加深⼊,否则会经常⾯临各种紧急CRUD操作,从⽽让代码结构混乱不堪,难以维护。

1.5.2、实战场景简介

        某地一商店为了回馈老客户,针对满足条件的老客户发放兑换卡、实物商品、优惠券三种奖品。其业务场景图如下:
图片1

1.5.3、开发环境

        本文将采用Java语言,基于JDK17基础环境、Maven、Idea等工具进行开发实现。JDK环境的安装请参考JDK安装部署。具体如下:

环境名称版本号
JDK1.8.0_202
Maven3.6.3
Idea2019.3.5

1.5.4、用传统的if-else语句实现

        如果不考虑任何扩展性,只为了尽快满⾜需求,那么对这么⼏种奖励发放只需使⽤ifelse语句判断,调⽤不同的接⼝即可满⾜需求。可能这也是⼀些刚⼊⻔编程的⼩伙伴,常⽤的⽅式。接下来我们就先按照这样的⽅式来实现业务的需求。

1.5.4.1、工程结构

        我们将借助Idea工具采用多模块的SpringBoot项目的方式构建工程结构,不会借助Idea工具创建多模块的SpringBoot项目的朋友请参考博文如何借助Idea创建多模块的SpringBoot项目,这里不再赘述,最终创建的工程结构如下图所示:
工程结构
        该工程结构按照严格的Spring MVC进行分层构建,主要包括:控制层、数据库访问层、数据实体和业务对象层、接口及接口实现层、启动类、资源文件及配置文件、单元测试类、pom文件等。而本示例主要用到了奖品入参对象AwardReqDTO、奖品出参对象AwardResDTO、兑换卡发放服务接口对象CardGiveService、优惠券发放服务接口对象CouponGiveService、实物商品发放服务接口对象GoodsGiveService、奖品发放服务接口对象AwardGiveService、兑换卡发放服务接口实现对象CardGiveServiceImpl、优惠券发放服务接口实现对象CouponGiveServiceImpl、实物商品发放服务接口实现对象GoodsGiveServiceImpl、奖品发放服务接口实现对象AwardGiveServiceImpl以及一个单元测试对象AwardGiveServiceTest,工程源码下载地址。

1.5.4.2、if-else需求实现
package cn.dz.smart.service.impl;import cn.dz.smart.pojo.dto.AwardReqDTO;
import cn.dz.smart.pojo.dto.AwardResDTO;
import cn.dz.smart.service.AwardGiveService;
import cn.dz.smart.service.CardGiveService;
import cn.dz.smart.service.CouponGiveService;
import cn.dz.smart.service.GoodsGiveService;
import cn.hutool.json.JSONUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;import java.util.Objects;/*** @ClassName AwardGiveServiceImpl.java* @Author wzd* @Version 1.0.0* @Description 奖品发放服务接口实现层* @CreateTime 2024年06月04日 22:56:00*/
@Slf4j
@Service
public class AwardGiveServiceImpl implements AwardGiveService {/*** @Description: 发放奖品* @Params: param 奖品发放参数* @Return: 是否发放成功* @Author: wzd* @Date: 2024年6月4日23:34:41*/@Overridepublic AwardResDTO give(AwardReqDTO param) {AwardResDTO result = null;if (Objects.nonNull(param)){String json = JSONUtil.toJsonStr(param);log.info("开始给用户编号为:{}的用户发放奖品。参数:{}", param.getUId(), json);if (param.getAwardType() == 1) {//发放优惠券CouponGiveService couponGiveService = new CouponGiveServiceImpl();Boolean give = couponGiveService.give();result = new AwardResDTO();if (give){result.setCode("000");result.setMessage("优惠券发放成功。");} else{result.setCode("001");result.setMessage("优惠券发放失败。");}} else if (param.getAwardType() == 2){//发放实物商品GoodsGiveService goodsGiveService = new GoodsGiveServiceImpl();Boolean give = goodsGiveService.give();result = new AwardResDTO();if (give){result.setCode("000");result.setMessage("实物商品发放成功。");} else{result.setCode("001");result.setMessage("实物商品发放失败。");}} else if (param.getAwardType() == 3){//发放兑换卡CardGiveService cardGiveService = new CardGiveServiceImpl();Boolean give = cardGiveService.give();result = new AwardResDTO();if (give){result.setCode("000");result.setMessage("兑换卡发放成功。");} else{result.setCode("001");result.setMessage("兑换卡发放失败。");}}}return result;}
}
  • 如上就是使⽤ if-else ⾮常直接的实现出来业务需求的非常糟糕的代码,如果仅从业务⻆度看,研发如期甚⾄提前实现了功能。
  • 那这样的代码⽬前来看并不会有什么问题,但如果在经过⼏次的迭代和拓展,接⼿这段代码的研发将⼗分痛苦。᯿构成本⾼需要理清之前每⼀个接⼝的使⽤,测试回归验证时间⻓,需要全部验证⼀次。这也就是很多⼈并不愿意接⼿别⼈的代码,如果接⼿了⼜被压榨开发时间。那么可想⽽知这样的 if-else 还会继续增加。这也是if-else实现的致命缺陷,因为每增加一个奖品发放类型就得增加一段if-else语句逻辑,也得重新测试回归验证一次。
1.5.4.3、测试验证

        写⼀个单元测试来验证上⾯编写的接⼝⽅式,养成单元测试的好习惯会为你增强代码质量。单元测试类代码如下:

package cn.dz.smart.test;import cn.dz.smart.pojo.dto.AwardReqDTO;
import cn.dz.smart.pojo.dto.AwardResDTO;
import cn.dz.smart.service.AwardGiveService;
import cn.dz.smart.service.impl.AwardGiveServiceImpl;
import cn.hutool.json.JSONUtil;
import lombok.extern.slf4j.Slf4j;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;/*** @ClassName AwardGiveServiceTest.java* @Author wzd* @Version 1.0.0* @Description 奖品发放测试类* @CreateTime 2024年06月04日 22:58:00*/
@Slf4j
@SpringBootTest
public class AwardGiveServiceTest {/*** @Description: 奖品发放单元测试方法* @Params: 无* @Return: 无* @Author: wzd* @Date: 2024年6月15日22:19:50*/@Testpublic void testGive(){AwardGiveService awardGiveService = new AwardGiveServiceImpl();System.out.println("111");log.info("模拟发放优惠券测试");AwardReqDTO param1 = new AwardReqDTO();param1.setUId("10001");param1.setAwardType(1);param1.setAwardCode("EGM1023938910232121323432");param1.setBizId("791098764902132");AwardResDTO give1 = awardGiveService.give(param1);log.info("请求参数:{}", JSONUtil.toJsonStr(param1));log.info("测试结果:{}", JSONUtil.toJsonStr(give1));log.info("模拟发放实物商品测试");AwardReqDTO param2 = new AwardReqDTO();param2.setUId("10002");param2.setAwardType(2);param2.setAwardCode("9820198721311");param2.setBizId("1023000020112221113");AwardResDTO give2 = awardGiveService.give(param2);log.info("请求参数:{}", JSONUtil.toJsonStr(param2));log.info("测试结果:{}", JSONUtil.toJsonStr(give2));log.info("模拟发放兑换卡测试");AwardReqDTO param3 = new AwardReqDTO();param3.setUId("10003");param3.setAwardType(3);param3.setAwardCode("AQY1xjk8LO975YUio");param3.setBizId("102300002011");AwardResDTO give3 = awardGiveService.give(param3);log.info("请求参数:{}", JSONUtil.toJsonStr(param3));log.info("测试结果:{}", JSONUtil.toJsonStr(give3));}
}

        测试结果如下:

模拟发放优惠券测试
开始给用户编号为:10001的用户发放奖品。参数:{"awardCode":"EGM1023938910232121323432","uId":"10001","bizId":"791098764902132","awardType":1}
请求参数:{"awardCode":"EGM1023938910232121323432","uId":"10001","bizId":"791098764902132","awardType":1}测试结果:{"code":"000","message":"优惠券发放成功。"}
模拟发放实物商品测试
开始给用户编号为:10002的用户发放奖品。参数:{"awardCode":"9820198721311","uId":"10002","bizId":"1023000020112221113","awardType":2}
请求参数:{"awardCode":"9820198721311","uId":"10002","bizId":"1023000020112221113","awardType":2}
测试结果:{"code":"000","message":"实物商品发放成功。"}
模拟发放兑换卡测试
开始给用户编号为:10003的用户发放奖品。参数:{"awardCode":"AQY1xjk8LO975YUio","uId":"10003","bizId":"102300002011","awardType":3}
请求参数:{"awardCode":"AQY1xjk8LO975YUio","uId":"10003","bizId":"102300002011","awardType":3}测试结果:{"code":"000","message":"兑换卡发放成功。"}
  • 运⾏结果正常,满⾜当前所有业务产品需求,写的还很快。但!实在难以为维护!

1.5.5、工厂模式优化代码

        接下来使⽤⼯⼚⽅法模式来进⾏代码优化,也算是⼀次很⼩的重构。整理᯿构会你会发现代码结构清晰了、也具备了下次新增业务需求的扩展性。但在实际使⽤中还会对此进⾏完善,⽬前的只是抽离出最核⼼的部分体现到你⾯前,⽅便学习。

1.5.5.1、工程结构

        工程结构与上面的if-else实现的工程结构类似,只是新增了公共接口对象CommodityService和工厂对象AwardFactory,具体如下:
工程结构1

  • ⾸先,从上⾯的⼯程结构中你是否⼀些感觉,⽐如:它看上去清晰了、这样分层可以更好扩展了、似乎可以想象到每⼀个类做了什么。
  • 如果还不能理解为什么这样修改,也没有关系。因为你是在通过这样的⽂章,来学习设计模式的魅⼒。并且再获取源码后,进⾏实际操作⼏次也就慢慢掌握了⼯⼚模式的技巧,,工程源码下载地址。
1.5.5.2、代码实现
1.5.5.2.1、定义各种商品发放接口及接口实现

        定义公共的奖品发奖接⼝,代码具体如下:

package cn.dz.smart.service;import cn.dz.smart.pojo.dto.AwardReqDTO;
import cn.dz.smart.pojo.dto.AwardResDTO;/*** @ClassName CommodityService.java* @Author wzd* @Version 1.0.0* @Description 奖品发放服务接口层* @CreateTime 2024年06月15日 21:47:00*/
public interface CommodityService {/*** 奖品发放接口*/AwardResDTO give(AwardReqDTO param);
}
  • 所有的奖品⽆论是实物、虚拟还是第三⽅兑换卡,都需要通过我们的程序实现此接⼝进⾏处理,以保证最终⼊参出参的统⼀性。

  • 接⼝的⼊参包括; ⽤户ID 、 奖品ID 、 业务ID 以及 扩展字段 ⽤于处理发放实物商品时的收货地址等。
            定义各类奖品发奖接⼝对象及接口实现对象,代码具体如下:

  • 兑换卡发放服务接口

package cn.dz.smart.service;/*** @ClassName CardGiveService.java* @Author wzd* @Version 1.0.0* @Description 兑换卡发放服务接口层* @CreateTime 2024年06月15日 21:51:00*/
public interface CardGiveService extends CommodityService {
}
  • 兑换卡发放服务接口实现
package cn.dz.smart.service.impl;import cn.dz.smart.pojo.dto.AwardReqDTO;
import cn.dz.smart.pojo.dto.AwardResDTO;
import cn.dz.smart.service.CardGiveService;
import org.springframework.stereotype.Service;/*** @ClassName CardGiveServiceImpl.java* @Author wzd* @Version 1.0.0* @Description 兑换卡发放服务接口实现层* @CreateTime 2024年06月15日 21:53:00*/
@Service
public class CardGiveServiceImpl implements CardGiveService {/*** @Description: 发放兑换卡* @Params: 无* @Return: 是否发放成功* @Author: wzd* @Date: 2024年6月15日21:58:29*/@Overridepublic AwardResDTO give(AwardReqDTO param) {return new AwardResDTO("000","兑换卡发放成功。");}
}
  • 优惠券发放服务接口
package cn.dz.smart.service;/*** @ClassName CouponGiveService.java* @Author wzd* @Version 1.0.0* @Description 优惠券发放服务接口层* @CreateTime 2024年06月15日 21:52:00*/
public interface CouponGiveService extends CommodityService {
}
  • 优惠券发放服务接口实现
package cn.dz.smart.service.impl;import cn.dz.smart.pojo.dto.AwardReqDTO;
import cn.dz.smart.pojo.dto.AwardResDTO;
import cn.dz.smart.service.CouponGiveService;
import org.springframework.stereotype.Service;/*** @ClassName CouponGiveServiceImpl.java* @Author wzd* @Version 1.0.0* @Description 优惠券发放服务接口实现层* @CreateTime 2024年06月15日 21:57:00*/
@Service
public class CouponGiveServiceImpl implements CouponGiveService {/*** @Description: 发放优惠券* @Params: 无* @Return: 是否发放成功* @Author: wzd* @Date: 2024年6月15日21:58:29*/@Overridepublic AwardResDTO give(AwardReqDTO param) {return new AwardResDTO("000","优惠券发放成功。");}
}
  • 实物商品发放服务接口
package cn.dz.smart.service;/*** @ClassName GoodsGiveService.java* @Author wzd* @Version 1.0.0* @Description 实物商品发放服务接口层* @CreateTime 2024年06月15日 21:52:00*/
public interface GoodsGiveService extends CommodityService {
}
  • 实物商品发放服务接口实现
package cn.dz.smart.service.impl;import cn.dz.smart.pojo.dto.AwardReqDTO;
import cn.dz.smart.pojo.dto.AwardResDTO;
import cn.dz.smart.service.GoodsGiveService;
import org.springframework.stereotype.Service;/*** @ClassName GoodsGiveServiceImpl.java* @Author wzd* @Version 1.0.0* @Description 实物商品发放服务接口实现层* @CreateTime 2024年06月15日 21:59:00*/
@Service
public class GoodsGiveServiceImpl implements GoodsGiveService {/*** @Description: 发放实物商品* @Params: 无* @Return: 是否发放成功* @Author: wzd* @Date: 2024年6月15日21:58:29*/@Overridepublic AwardResDTO give(AwardReqDTO param) {return new AwardResDTO("000","实物商品发放成功。");}
}
  • 从上⾯可以看到每⼀种奖品的实现都包括在⾃⼰的类中,新增、修改或者删除都不会影响其他奖品功能的测试,降低回归测试的可能。
  • 后续在新增的奖品只需要按照此结构进⾏填充即可,⾮常易于维护和扩展。
  • 在统⼀了⼊参以及出参后,调⽤⽅不在需要关⼼奖品发放的内部逻辑,按照统⼀的⽅式即可处理。
1.5.5.2.2、定义工厂及统一的发放接口及接口实现

        定义工厂,代码具体如下:

package cn.dz.smart.factory;import cn.dz.smart.service.CommodityService;
import cn.dz.smart.service.impl.CardGiveServiceImpl;
import cn.dz.smart.service.impl.CouponGiveServiceImpl;
import cn.dz.smart.service.impl.GoodsGiveServiceImpl;import java.util.Objects;/*** @ClassName AwardFactory.java* @Author wzd* @Version 1.0.0* @Description 商店奖品工厂类* @CreateTime 2024年06月15日 22:04:00*/
public class AwardFactory {/*** @Description: 根据奖品类型创建奖品发放工厂服务类* @Params: awardType 奖品类型,1优惠券、2实物商品、3第三⽅兑换卡* @Return: 奖品发放工厂服务类* @Author: wzd* @Date:*/public CommodityService getAwardFactory(Integer awardType){if (Objects.isNull(awardType)) return null;if (1==awardType) return new CouponGiveServiceImpl();if (2==awardType) return new GoodsGiveServiceImpl();if (3==awardType) return new CardGiveServiceImpl();throw new RuntimeException("不存在的商品服务类型");}
}

        定义统一的发放接口,代码具体如下:

package cn.dz.smart.service;/*** @ClassName AwardGiveService.java* @Author wzd* @Version 1.0.0* @Description 奖品发放服务接口层* @CreateTime 2024年06月15日 22:13:00*/
public interface AwardGiveService extends CommodityService {
}

        定义统一的发放接口实现,代码具体如下:

package cn.dz.smart.service.impl;import cn.dz.smart.factory.AwardFactory;
import cn.dz.smart.pojo.dto.AwardReqDTO;
import cn.dz.smart.pojo.dto.AwardResDTO;
import cn.dz.smart.service.AwardGiveService;
import cn.dz.smart.service.CommodityService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;import java.util.Objects;/*** @ClassName AwardGiveServiceImpl.java* @Author wzd* @Version 1.0.0* @Description 奖品发放服务接口实现层* @CreateTime 2024年06月15日 22:11:00*/
@Slf4j
@Service
public class AwardGiveServiceImpl implements AwardGiveService {/*** @Description: 发放奖品* @Params: param 奖品发放参数* @Return: 是否发放成功* @Author: wzd* @Date: 2024年6月15日22:15:08*/@Overridepublic AwardResDTO give(AwardReqDTO param) {//实例化工厂AwardFactory factory = new AwardFactory();//根据奖品类型创建对应的奖品发放服务类CommodityService service = factory.getAwardFactory(param.getAwardType());if (Objects.isNull(service)) return null;return service.give(param);}
}
  • 这⾥我们定义了⼀个工厂类,在⾥⾯按照类型实现各种商品的服务。可以⾮常⼲净整洁的处理你的代码,后续新增的商品在这⾥扩展即可。如果你不喜欢 if 判断,也可以使⽤ switch 或者 map 配置结构,会让代码更加⼲净。
  • 另外很多代码检查软件和编码要求,不喜欢if语句后⾯不写扩展,这⾥是为了更加⼲净的向你体现
    逻辑。在实际的业务编码中可以添加括号。
1.5.5.3、测试验证

        单元测试类代码如下:

package cn.dz.smart.test;import cn.dz.smart.pojo.dto.AwardReqDTO;
import cn.dz.smart.pojo.dto.AwardResDTO;
import cn.dz.smart.service.AwardGiveService;
import cn.dz.smart.service.impl.AwardGiveServiceImpl;
import cn.hutool.json.JSONUtil;
import lombok.extern.slf4j.Slf4j;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;/*** @ClassName AwardGiveServiceTest.java* @Author wzd* @Version 1.0.0* @Description 奖品发放测试类* @CreateTime 2024年06月15日 22:19:00*/
@Slf4j
@SpringBootTest
public class AwardGiveServiceTest {/*** @Description: 奖品发放单元测试方法* @Params: 无* @Return: 无* @Author: wzd* @Date: 2024年6月15日22:19:50*/@Testpublic void testGive(){AwardGiveService awardGiveService = new AwardGiveServiceImpl();System.out.println("111");log.info("模拟发放优惠券测试");AwardReqDTO param1 = new AwardReqDTO();param1.setUId("10001");param1.setAwardType(1);param1.setAwardCode("EGM1023938910232121323432");param1.setBizId("791098764902132");AwardResDTO give1 = awardGiveService.give(param1);log.info("请求参数:{}", JSONUtil.toJsonStr(param1));log.info("测试结果:{}", JSONUtil.toJsonStr(give1));log.info("模拟发放实物商品测试");AwardReqDTO param2 = new AwardReqDTO();param2.setUId("10002");param2.setAwardType(2);param2.setAwardCode("9820198721311");param2.setBizId("1023000020112221113");AwardResDTO give2 = awardGiveService.give(param2);log.info("请求参数:{}", JSONUtil.toJsonStr(param2));log.info("测试结果:{}", JSONUtil.toJsonStr(give2));log.info("模拟发放兑换卡测试");AwardReqDTO param3 = new AwardReqDTO();param3.setUId("10003");param3.setAwardType(3);param3.setAwardCode("AQY1xjk8LO975YUio");param3.setBizId("102300002011");AwardResDTO give3 = awardGiveService.give(param3);log.info("请求参数:{}", JSONUtil.toJsonStr(param3));log.info("测试结果:{}", JSONUtil.toJsonStr(give3));}
}

        测试结果如下:

模拟发放优惠券测试
开始给用户编号为:10001的用户发放奖品。参数:{"awardCode":"EGM1023938910232121323432","uId":"10001","bizId":"791098764902132","awardType":1}
请求参数:{"awardCode":"EGM1023938910232121323432","uId":"10001","bizId":"791098764902132","awardType":1}测试结果:{"code":"000","message":"优惠券发放成功。"}
模拟发放实物商品测试
开始给用户编号为:10002的用户发放奖品。参数:{"awardCode":"9820198721311","uId":"10002","bizId":"1023000020112221113","awardType":2}
请求参数:{"awardCode":"9820198721311","uId":"10002","bizId":"1023000020112221113","awardType":2}
测试结果:{"code":"000","message":"实物商品发放成功。"}
模拟发放兑换卡测试
开始给用户编号为:10003的用户发放奖品。参数:{"awardCode":"AQY1xjk8LO975YUio","uId":"10003","bizId":"102300002011","awardType":3}
请求参数:{"awardCode":"AQY1xjk8LO975YUio","uId":"10003","bizId":"102300002011","awardType":3}测试结果:{"code":"000","message":"兑换卡发放成功。"}
  • 运⾏结果正常,既满⾜了业务产品需求,也满⾜了⾃⼰对代码的追求。这样的代码部署上线运⾏,内⼼不会恐慌,不会觉得半夜会有电话。
  • 另外从运⾏测试结果上也可以看出来,在进⾏封装后可以⾮常清晰的看到⼀整套发放奖品服务的完整性,统⼀了⼊参、统⼀了结果。

1.5.6、总结

  • 从上到下的优化来看,⼯⼚⽅法模式并不复杂,甚⾄这样的开发结构在你有所理解后,会发现更加简单了。
  • 那么这样的开发的好处知道后,也可以总结出来它的优点; 避免创建者与具体的产品逻辑耦合 、 满足单⼀职责,每⼀个业务逻辑实现都在所属⾃⼰的类中完成 、 满足开闭原则,无需更改使⽤调⽤⽅就可以在程序中引⼊新的产品类型 。但这样也会带来⼀些问题,⽐如有⾮常多的奖品类型,那么实现的子类会极速扩张。因此也需要使⽤其他的模式进⾏优化,这些在后续的设计模式中会逐步涉及到。
  • 从案例入手看设计模式往往要⽐看理论学的更加容易,因为案例是缩短理论到上⼿的最佳⽅式,如果你已经有所收获,⼀定要去尝试实操。
  • 完整的工程源码下载地址。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/pingmian/28379.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Android开发系列:高性能视图组件Surfaceview

一、Surfaceview概述 在Android应用开发领域,面对视频播放、游戏构建及相机实时预览等高性能需求场景,直接操控图像数据并即时展示于屏幕成为必要条件。传统View组件在此类情境下显现局限性: 性能瓶颈:传统View的绘制任务由UI主…

Spring系统学习 -Spring IOC 的XML管理Bean之类类型属性赋值、数组类型属性赋值、集合类属性赋值

类类型属性赋值&#xff1a; 在XML配置中&#xff0c;可以使用 <property> 元素为类类型属性赋值。通过指定属性的名称和值&#xff0c;可以直接将其他Bean的实例引用注入到目标Bean的属性中。这种方式可以建立对象之间的关联关系。例如&#xff0c;可以将一个Address对象…

Element-UI - 解决el-table中图片悬浮被遮挡问题

在开发中&#xff0c;发现element-ui在el-table中添加图片悬浮显示时&#xff0c;会被单元格遮挡的问题。通过查询得到的解决办法&#xff0c;大多是修改.el-table类中相关样式属性&#xff0c;但经过验证发现会影响到其他正常功能的使用。对于此问题解决其实也并不难&#xff…

生产者消费者模型的同步与互斥:C++代码实现

文章目录 一、引言二、生产者消费者模型概述1、基本概念和核心思想2、生产者消费者模型的优点 三、消费者和生产者之间的同步与互斥四、代码实现1、事前准备2、环形队列的实现3、阻塞队列的实现4、两种实现方式的区别 一、引言 在现代计算机系统中&#xff0c;很多任务需要同时…

【机器学习】机器学习与教育科技在个性化教学中的融合应用与性能优化新探索

文章目录 引言机器学习与教育科技的基本概念机器学习概述监督学习无监督学习强化学习 教育科技概述学生学习行为分析个性化学习路径推荐智能化教育评估 机器学习与教育科技的融合应用实时学习数据分析数据预处理特征工程 学生成绩预测与优化模型训练模型评估 个性化学习路径推荐…

【AI实践】Ollama本地安装大模型服务

Ollama安装运行 安装与配置 Download Ollama 安装默认在C盘&#xff0c;成功后&#xff0c;window任务栏图标会有Ollama Logo 为了不占用C盘更大的空间&#xff0c;修改模型下载路径&#xff0c;修改环境变量 下载模型 由于我电脑是第六代Intel&#xff0c;集显&#xff0c;…

【算法题】搜索二维矩阵,一文彻底弄会!

目录 一、题目描述 二、解题思路 1、引言 2、思路推导过程 三、参考答案 一、题目描述 搜索二维矩阵 给你一个满足下述两条属性的 m x n 整数矩阵&#xff1a; 每行中的整数从左到右按非严格递增顺序排列。每行的第一个整数大于前一行的最后一个整数。 给你一个整数…

【C++】多态|原理|override|final|抽象类|多继承虚函数表|对象模型|虚表打印|(万字详解版)

目录 ​编辑 一.多态的概念 二.多态的构建 虚函数 重写 虚函数重写的例外 协变 隐藏 析构函数的重写 三.重载、重写(覆盖)、隐藏(重定义)的对比 四.C11新增的 override 和 final override final 五.抽象类 六.多态的原理 虚函数表 总结&#xff1a; 引用…

非常好用的7个Vue3组件库!!【送源码】

说到Vue&#xff0c;怎能不提Vue3呢&#xff1f; 它的大名鼎鼎主要归功于一项革命性的创新——Composition API。 这个新功能为逻辑复用带来了前所未有的友好性和灵活性&#xff0c;让开发者们在构建应用时如鱼得水。 如果你现在正在使用Vue3&#xff0c;或者在新的一年考虑…

浏览器上直接运行近 1000个 AI 模型!

今天推荐的开源项目叫做 tansformers.js&#xff0c;这是一个不需要服务器端&#xff0c;能让你在浏览器上使用到自然语言处理、计算机视觉等 AI 能力的开源项目。由 xenova 开源&#xff0c;transformers.js 已经在 GitHub 上获得了超过 9.2K 颗星星。 项目简介 transformers.…

JVM如何确定方法调用

方法调用并不等同于方法执行&#xff0c;方法调用阶段唯一的任务就是确定调用哪一个方法&#xff0c;不涉及方法内部的具体运行过程。在程序运行时&#xff0c;进行方法调用是最普遍、最频繁的操作&#xff0c;但Class文件的编译过程中不包含传统编译中的连接步骤&#xff0c;一…

医学人工智能项目如何申请基金?

小罗碎碎念 本期推文面向的群体 青年教师有志硕博/博后 尤其适合一直认真追小罗推文的老师/同学&#xff0c;你们会发现自己在看这篇推文的时候&#xff0c;遇到自己领域的项目时&#xff0c;文思如泉涌&#xff0c;仿佛马上就能把本子写好&#xff0c;哈哈。&#xff08;运用…

命令词:引导行动的语言工具

人不走空 &#x1f308;个人主页&#xff1a;人不走空 &#x1f496;系列专栏&#xff1a;算法专题 ⏰诗词歌赋&#xff1a;斯是陋室&#xff0c;惟吾德馨 目录 &#x1f308;个人主页&#xff1a;人不走空 &#x1f496;系列专栏&#xff1a;算法专题 ⏰诗词歌…

App UI 风格打造独特体验

App UI 风格打造独特体验

通过Stream流对集合进行操作

Stream Api是JDK8提供的新特性&#xff0c;可以更为方便地对集合进行操作&#xff0c;比如我今天遇到的一个场景&#xff1a; 将本地的一个视频文件分成多块上传到Minio服务器&#xff0c;现在上传功能已经完成&#xff0c;需要调用minioClient对已经上传的文件重新合并成一个新…

8086汇编 add指令学习

ADD&#xff0c;是Intel x86平台的汇编加法指令&#xff0c;MEM代指操作数为内存或寄存器&#xff0c;REG代指操作数为寄存器&#xff0c;IMM代指立即数&#xff0c;SEG代指操作数为段寄存器。 形式和示例如下&#xff1b; ADD MEM8,REG8 ADD DS:[BXSI],AL ADD MEM16,R…

【ARM Coresight Debug 系列 -- ARMv8/v9 Watchpoint 软件实现地址监控详细介绍】

请阅读【嵌入式开发学习必备专栏 】 文章目录 ARMv8/v9 Watchpoint exceptionsWatchpoint 配置信息读取Execution conditionsWatchpoint data address comparisonsSize of the data accessWatchpoint 软件配置流程Watchpoint Type 使用介绍WT, Bit [20]: Watchpoint TypeLBN, B…

vue技巧(十)全局配置使用(打包后可修改配置文件)

1、背景 vue打包目前主流用的有webpack和vite两种&#xff0c;默认用的webpack。&#xff08;二者的区别大家可以各自上网查&#xff0c;我没用过vite&#xff0c;所以不过多介绍&#xff09;vue通过webpack打包后&#xff0c;源码会被压缩&#xff0c;但一些关键配置可…

【新课程】PICO VR 交互开发指南

从PICO开始&#xff0c;迈向XR跨平台开发 Unity XR Interaction Toolkit &#xff08;简称XRI&#xff09;是一套跨平台的 XR 交互开发工具包&#xff0c;随着版本的更新与完善&#xff0c;逐渐获得了开发者的青睐。各 XR 平台逐步推荐开发者采用 XRI 作为首选的交互开发工具为…

Pytest框架中fixture功能详解

文章目录 1 定义 Fixture函数 2 Fixture 的函数参数 2.1 传入其他fixture函数作为参数 2.2 传入request对象参数 示例1&#xff1a;访问fixture的调用者 示例2&#xff1a;使用fixture的参数 3 Fixture 的作用域参数scope 3.1 scopeclass场景 3.2 scopesession场景 4…