⼯⼚⽅法模式

news2024/11/15 10:18:07

⼯⼚⽅法模式

⼯⼚⽅法模式,属于创建者模式中的一种,这类模式提供创建对象的机制, 能够提升已有代码的灵活性和可复⽤性。

创建者模式包括:⼯⼚⽅法、抽象⼯⼚、⽣成器、原型、单例,这5类。

1.⼯⼚⽅法模式介绍

image-20230101155734100

⼯⼚模式⼜称⼯⼚⽅法模式,是⼀种创建型设计模式,其在⽗类中提供⼀个创建对象的⽅法, 允许⼦类

决定实例化对象的类型。

这种设计模式也是 Java 开发中最常⻅的⼀种模式,它的主要意图是定义⼀个创建对象的接⼝,让其⼦

类⾃⼰决定实例化哪⼀个⼯⼚类,⼯⼚模式使其创建过程延迟到⼦类进⾏。

简单说就是为了提供代码结构的扩展性,屏蔽每⼀个功能类中的具体实现逻辑。让外部可以更加简单的

只是知道调⽤即可,同时,这也是去掉众多 ifelse 的⽅式。当然这可能也有⼀些缺点,⽐如需要实现

的类⾮常多,如何去维护,怎样减低开发成本。但这些问题都可以在后续的设计模式结合使⽤中,逐步

降低。

2.模拟发奖多种商品

image-20230101155915229

这⾥模拟互联⽹中在营销场景下的业务。由于营销场景

的复杂、多变、临时的特性,它所需要的设计需要更加深⼊,否则会经常⾯临各种紧急CRUD操作,从

⽽让代码结构混乱不堪,难以维护。

在营销场景中经常会有某个⽤户做了⼀些操作;打卡、分享、留⾔、邀请注册等等,进⾏返利积分,最

后通过积分在兑换商品,从⽽促活和拉新。

那么在这⾥我们模拟积分兑换中的发放多种类型商品,假如现在我们有如下三种类型的商品接⼝;

序号类型接⼝
1优惠券CouponResult sendCoupon(String uId, String couponNumber, String uuid)
2实物商品Boolean deliverGoods(DeliverReq req)
3第三⽅爱奇艺void grantToken(String bindMobileNumber, String cardId)

从以上接⼝来看有如下信息:

  • 三个接⼝返回类型不同,有对象类型、布尔类型、还有⼀个空类型。

  • ⼊参不同,发放优惠券需要仿重、兑换卡需要卡ID、实物商品需要发货位置(对象中含有)。

  • 另外可能会随着后续的业务的发展,会新增其他种商品类型。因为你所有的开发需求都是随着业务

​ 对市场的拓展⽽带来的。

如果不考虑任何扩展性,只为了尽快满⾜需求,那么对这么⼏种奖励发放只需使⽤ifelse语句判断,调

⽤不同的接⼝即可满⾜需求。可能这也是⼀些刚⼊⻔编程的⼩伙伴,常⽤的⽅式。接下来我们就先按照

这样的⽅式来实现业务的需求。

3.用⼀坨坨代码实现

代码实现

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

/**
 * 模拟发奖服务
 */
public class PrizeController {

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

    public AwardRes awardToUser(AwardReq req) {
        String reqJson = JSON.toJSONString(req);
        //模拟接收发放奖品响应
        AwardRes awardRes = null;
        try {
            logger.info("奖品发放开始{}。req:{}", req.getuId(), reqJson);
            // 按照不同类型方法商品[1优惠券、2实物商品、3第三方兑换卡(爱奇艺)]
            if (req.getAwardType() == 1) {
                CouponService couponService = new CouponService();
                CouponResult couponResult = couponService.sendCoupon(req.getuId(), req.getAwardNumber(), req.getBizId());
                if ("0000".equals(couponResult.getCode())) {
                    awardRes = new AwardRes("0000", "发放成功");
                } else {
                    awardRes = new AwardRes("0001", couponResult.getInfo());
                }
            } else if (req.getAwardType() == 2) {
                GoodsService goodsService = new GoodsService();
                DeliverReq deliverReq = new DeliverReq();
                deliverReq.setUserName(queryUserName(req.getuId()));
                deliverReq.setUserPhone(queryUserPhoneNumber(req.getuId()));
                deliverReq.setSku(req.getAwardNumber());
                deliverReq.setOrderId(req.getBizId());
                deliverReq.setConsigneeUserName(req.getExtMap().get("consigneeUserName"));
                deliverReq.setConsigneeUserPhone(req.getExtMap().get("consigneeUserPhone"));
                deliverReq.setConsigneeUserAddress(req.getExtMap().get("consigneeUserAddress"));
                Boolean isSuccess = goodsService.deliverGoods(deliverReq);
                if (isSuccess) {
                    awardRes = new AwardRes("0000", "发放成功");
                } else {
                    awardRes = new AwardRes("0001", "发放失败");
                }
            } else if (req.getAwardType() == 3) {
                String bindMobileNumber = queryUserPhoneNumber(req.getuId());
                IQiYiCardService iQiYiCardService = new IQiYiCardService();
                iQiYiCardService.grantToken(bindMobileNumber, req.getAwardNumber());
                awardRes = new AwardRes("0000", "发放成功");
            }
            logger.info("奖品发放完成{}。", req.getuId());
        } catch (Exception e) {
            logger.error("奖品发放失败{}。req:{}", req.getuId(), reqJson, e);
            awardRes = new AwardRes("0001", e.getMessage());
        }

        return awardRes;
    }

    private String queryUserName(String uId) {
        return "花花";
    }

    private String queryUserPhoneNumber(String uId) {
        return "15200101232";
    }

}

如上就是使⽤ ifelse ⾮常直接的实现出来业务需求的⼀坨代码,如果仅从业务⻆度看,

研发如期甚⾄提前实现了功能。

那这样的代码⽬前来看并不会有什么问题,但如果在经过⼏次的迭代和拓展,接⼿这段代码的研发

将⼗分痛苦。᯿构成本⾼需要理清之前每⼀个接⼝的使⽤,测试回归验证时间⻓,需要全部验证⼀

次。这也就是很多⼈并不愿意接⼿别⼈的代码,如果接⼿了⼜被压榨开发时间。那么可想⽽知这样

的 ifelse 还会继续增加。

测试验证

public class ApiTest {

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

    @Test
    public void test_awardToUser() {

        PrizeController prizeController = new PrizeController();

        System.out.println("\r\n模拟发放优惠券测试\r\n");
        // 模拟发放优惠券测试
        AwardReq req01 = new AwardReq();
        req01.setuId("10001");
        req01.setAwardType(1);
        req01.setAwardNumber("EGM1023938910232121323432");
        req01.setBizId("791098764902132");
        AwardRes awardRes01 = prizeController.awardToUser(req01);

        logger.info("请求参数:{}", JSON.toJSON(req01));
        logger.info("测试结果:{}", JSON.toJSON(awardRes01));

        System.out.println("\r\n模拟方法实物商品\r\n");
        // 模拟方法实物商品
        AwardReq req02 = new AwardReq();
        req02.setuId("10001");
        req02.setAwardType(2);
        req02.setAwardNumber("9820198721311");
        req02.setBizId("1023000020112221113");
        req02.setExtMap(new HashMap<String, String>() {{
            put("consigneeUserName", "谢飞机");
            put("consigneeUserPhone", "15200292123");
            put("consigneeUserAddress", "吉林省.长春市.双阳区.XX街道.檀溪苑小区.#18-2109");
        }});

        AwardRes awardRes02 = prizeController.awardToUser(req02);
        logger.info("请求参数:{}", JSON.toJSON(req02));
        logger.info("测试结果:{}", JSON.toJSON(awardRes02));
        
        //模拟发放爱奇艺会员
        System.out.println("\r\n第三方兑换卡(爱奇艺)\r\n");
        AwardReq req03 = new AwardReq();
        req03.setuId("10001");
        req03.setAwardType(3);
        req03.setAwardNumber("AQY1xjkUodl8LO975GdfrYUio");

        AwardRes awardRes03 = prizeController.awardToUser(req03);
        logger.info("请求参数:{}", JSON.toJSON(req03));
        logger.info("测试结果:{}", JSON.toJSON(awardRes03));

    }

}

测试结果

模拟发放优惠券测试

22:17:55.668 [main] INFO  o.i.demo.design.PrizeController - 奖品发放开始10001。req:{"awardNumber":"EGM1023938910232121323432","awardType":1,"bizId":"791098764902132","uId":"10001"}
模拟发放优惠券一张:10001,EGM1023938910232121323432,791098764902132
22:17:55.671 [main] INFO  o.i.demo.design.PrizeController - 奖品发放完成1000122:17:55.673 [main] INFO  org.itstack.demo.test.ApiTest - 请求参数:{"uId":"10001","bizId":"791098764902132","awardNumber":"EGM1023938910232121323432","awardType":1}
22:17:55.674 [main] INFO  org.itstack.demo.test.ApiTest - 测试结果:{"code":"0000","info":"发放成功"}

模拟方法实物商品

22:17:55.675 [main] INFO  o.i.demo.design.PrizeController - 奖品发放开始10001。req:{"awardNumber":"9820198721311","awardType":2,"bizId":"1023000020112221113","extMap":{"consigneeUserName":"谢飞机","consigneeUserPhone":"15200292123","consigneeUserAddress":"吉林省.长春市.双阳区.XX街道.檀溪苑小区.#18-2109"},"uId":"10001"}
模拟发货实物商品一个:{"consigneeUserAddress":"吉林省.长春市.双阳区.XX街道.檀溪苑小区.#18-2109","consigneeUserName":"谢飞机","consigneeUserPhone":"15200292123","orderId":"1023000020112221113","sku":"9820198721311","userName":"花花","userPhone":"15200101232"}
22:17:55.677 [main] INFO  o.i.demo.design.PrizeController - 奖品发放完成1000122:17:55.677 [main] INFO  org.itstack.demo.test.ApiTest - 请求参数:{"extMap":{"consigneeUserName":"谢飞机","consigneeUserAddress":"吉林省.长春市.双阳区.XX街道.檀溪苑小区.#18-2109","consigneeUserPhone":"15200292123"},"uId":"10001","bizId":"1023000020112221113","awardNumber":"9820198721311","awardType":2}
22:17:55.677 [main] INFO  org.itstack.demo.test.ApiTest - 测试结果:{"code":"0000","info":"发放成功"}

第三方兑换卡(爱奇艺)

22:17:55.678 [main] INFO  o.i.demo.design.PrizeController - 奖品发放开始10001。req:{"awardNumber":"AQY1xjkUodl8LO975GdfrYUio","awardType":3,"uId":"10001"}
模拟发放爱奇艺会员卡一张:15200101232AQY1xjkUodl8LO975GdfrYUio
22:17:55.678 [main] INFO  o.i.demo.design.PrizeController - 奖品发放完成1000122:17:55.678 [main] INFO  org.itstack.demo.test.ApiTest - 请求参数:{"uId":"10001","awardNumber":"AQY1xjkUodl8LO975GdfrYUio","awardType":3}
22:17:55.678 [main] INFO  org.itstack.demo.test.ApiTest - 测试结果:{"code":"0000","info":"发放成功"}

Process finished with exit code 0

4.⼯⼚模式优化代码

代码实现

定义发奖接口

public interface ICommodity {
 void sendCommodity(String uId, String commodityId, String bizId,
Map<String, String> extMap) throws Exception;
}

所有的奖品⽆论是实物、虚拟还是第三⽅,都需要通过我们的程序实现此接⼝进⾏处理,以保证最

终⼊参出参的统⼀性。

接⼝的⼊参包括; ⽤户ID 、 奖品ID 、 业务ID 以及 扩展字段 ⽤于处理发放实物商品时的收获地址。

实现奖品发放接⼝

优惠券

//优惠卷
public class CouponCommodityService implements ICommodity {

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

    private CouponService couponService = new CouponService();

    public void sendCommodity(String uId, String commodityId, String bizId, Map<String, String> extMap) throws Exception {
        CouponResult couponResult = couponService.sendCoupon(uId, commodityId, bizId);
        logger.info("请求参数[优惠券] => uId:{} commodityId:{} bizId:{} extMap:{}", uId, commodityId, bizId, JSON.toJSON(extMap));
        logger.info("测试结果[优惠券]:{}", JSON.toJSON(couponResult));
        if (!"0000".equals(couponResult.getCode())) throw new RuntimeException(couponResult.getInfo());
    }

}

实物商品

public class GoodsCommodityService implements ICommodity {

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

    private GoodsService goodsService = new GoodsService();

    public void sendCommodity(String uId, String commodityId, String bizId, Map<String, String> extMap) throws Exception {
        DeliverReq deliverReq = new DeliverReq();
        deliverReq.setUserName(queryUserName(uId));
        deliverReq.setUserPhone(queryUserPhoneNumber(uId));
        deliverReq.setSku(commodityId);
        deliverReq.setOrderId(bizId);
        deliverReq.setConsigneeUserName(extMap.get("consigneeUserName"));
        deliverReq.setConsigneeUserPhone(extMap.get("consigneeUserPhone"));
        deliverReq.setConsigneeUserAddress(extMap.get("consigneeUserAddress"));

        Boolean isSuccess = goodsService.deliverGoods(deliverReq);

        logger.info("请求参数[优惠券] => uId:{} commodityId:{} bizId:{} extMap:{}", uId, commodityId, bizId, JSON.toJSON(extMap));
        logger.info("测试结果[优惠券]:{}", isSuccess);

        if (!isSuccess) throw new RuntimeException("实物商品发放失败");
    }

    private String queryUserName(String uId) {
        return "花花";
    }

    private String queryUserPhoneNumber(String uId) {
        return "15200101232";
    }

}

第三方兑换卡

public class CardCommodityService implements ICommodity {

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

    // 模拟注入
    private IQiYiCardService iQiYiCardService = new IQiYiCardService();

    public void sendCommodity(String uId, String commodityId, String bizId, Map<String, String> extMap) throws Exception {
        String mobile = queryUserMobile(uId);
        iQiYiCardService.grantToken(mobile, bizId);
        logger.info("请求参数[爱奇艺兑换卡] => uId:{} commodityId:{} bizId:{} extMap:{}", uId, commodityId, bizId, JSON.toJSON(extMap));
        logger.info("测试结果[爱奇艺兑换卡]:success");
    }

    private String queryUserMobile(String uId) {
        return "15200101232";
    }

}
  • 从上面可以看到每一种奖品的实现都包括在自己的类中,新增、修改或者删除都不会影响其他奖品功能的测试,降低回归测试的可能。
  • 后续在新增的奖品只需要按照此结构进行填充即可,非常易于维护和扩展。
  • 在统一了入参以及出参后,调用方不在需要关心奖品发放的内部逻辑,按照统一的方式即可处理。

创建商店工厂

public class StoreFactory {

    public ICommodity getCommodityService(Integer commodityType) {
        if (null == commodityType) return null;
        if (1 == commodityType) return new CouponCommodityService();
        if (2 == commodityType) return new GoodsCommodityService();
        if (3 == commodityType) return new CardCommodityService();
        throw new RuntimeException("不存在的商品服务类型");
    }

}
  • 这里我们定义了一个商店的工厂类,在里面按照类型实现各种商品的服务。可以非常干净整洁的处理你的代码,后续新增的商品在这里扩展即可。如果你不喜欢if判断,也可以使用switch或者map配置结构,会让代码更加干净。
  • 另外很多代码检查软件和编码要求,不喜欢if语句后面不写扩展,这里是为了更加干净的向你体现逻辑。在实际的业务编码中可以添加括号。

测试验证

@Test
public void test_commodity() throws Exception {
    StoreFactory storeFactory = new StoreFactory();
    // 1. 优惠券
    ICommodity commodityService_1 = storeFactory.getCommodityService(1);
    commodityService_1.sendCommodity("10001", "EGM1023938910232121323432", "791098764902132", null);
    // 2. 实物商品
    ICommodity commodityService_2 = storeFactory.getCommodityService(2);
    
    Map<String,String> extMap = new HashMap<String,String>();
    extMap.put("consigneeUserName", "谢飞机");
    extMap.put("consigneeUserPhone", "15200292123");
    extMap.put("consigneeUserAddress", "吉林省.长春市.双阳区.XX街道.檀溪苑小区.#18-2109");

    commodityService_2.sendCommodity("10001","9820198721311","1023000020112221113", extMap);
    // 3. 第三方兑换卡(爱奇艺)
    ICommodity commodityService_3 = storeFactory.getCommodityService(3);
    commodityService_3.sendCommodity("10001","AQY1xjkUodl8LO975GdfrYUio",null,null);
}
模拟发放优惠券测试

22:17:55.668 [main] INFO  o.i.demo.design.PrizeController - 奖品发放开始10001。req:{"awardNumber":"EGM1023938910232121323432","awardType":1,"bizId":"791098764902132","uId":"10001"}
模拟发放优惠券一张:10001,EGM1023938910232121323432,791098764902132
22:17:55.671 [main] INFO  o.i.demo.design.PrizeController - 奖品发放完成1000122:17:55.673 [main] INFO  org.itstack.demo.test.ApiTest - 请求参数:{"uId":"10001","bizId":"791098764902132","awardNumber":"EGM1023938910232121323432","awardType":1}
22:17:55.674 [main] INFO  org.itstack.demo.test.ApiTest - 测试结果:{"code":"0000","info":"发放成功"}

模拟方法实物商品

22:17:55.675 [main] INFO  o.i.demo.design.PrizeController - 奖品发放开始10001。req:{"awardNumber":"9820198721311","awardType":2,"bizId":"1023000020112221113","extMap":{"consigneeUserName":"谢飞机","consigneeUserPhone":"15200292123","consigneeUserAddress":"吉林省.长春市.双阳区.XX街道.檀溪苑小区.#18-2109"},"uId":"10001"}
模拟发货实物商品一个:{"consigneeUserAddress":"吉林省.长春市.双阳区.XX街道.檀溪苑小区.#18-2109","consigneeUserName":"谢飞机","consigneeUserPhone":"15200292123","orderId":"1023000020112221113","sku":"9820198721311","userName":"花花","userPhone":"15200101232"}
22:17:55.677 [main] INFO  o.i.demo.design.PrizeController - 奖品发放完成1000122:17:55.677 [main] INFO  org.itstack.demo.test.ApiTest - 请求参数:{"extMap":{"consigneeUserName":"谢飞机","consigneeUserAddress":"吉林省.长春市.双阳区.XX街道.檀溪苑小区.#18-2109","consigneeUserPhone":"15200292123"},"uId":"10001","bizId":"1023000020112221113","awardNumber":"9820198721311","awardType":2}
22:17:55.677 [main] INFO  org.itstack.demo.test.ApiTest - 测试结果:{"code":"0000","info":"发放成功"}

第三方兑换卡(爱奇艺)

22:17:55.678 [main] INFO  o.i.demo.design.PrizeController - 奖品发放开始10001。req:{"awardNumber":"AQY1xjkUodl8LO975GdfrYUio","awardType":3,"uId":"10001"}
模拟发放爱奇艺会员卡一张:15200101232AQY1xjkUodl8LO975GdfrYUio
22:17:55.678 [main] INFO  o.i.demo.design.PrizeController - 奖品发放完成1000122:17:55.678 [main] INFO  org.itstack.demo.test.ApiTest - 请求参数:{"uId":"10001","awardNumber":"AQY1xjkUodl8LO975GdfrYUio","awardType":3}
22:17:55.678 [main] INFO  org.itstack.demo.test.ApiTest - 测试结果:{"code":"0000","info":"发放成功"}

Process finished with exit code 0
 

5.总结

  • 根据不同的类型处理不同业务,或者需要实现不同的业务逻辑,可以考虑使用工厂模式
  • 那么这样的开发的好处知道后,也可以总结出来它的优点;避免创建者与具体的产品逻辑耦合满足单一职责,每一个业务逻辑实现都在所属自己的类中完成满足开闭原则,无需更改使用调用方就可以在程序中引入新的产品类型。但这样也会带来一些问题,比如有非常多的奖品类型,那么实现的子类会极速扩张。因此也需要使用其他的模式进行优化。

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

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

相关文章

LaoCat带你认识容器与镜像(二【一章】)

系列二章&#xff0c;祝大家新的一年事事顺心&#xff0c;想要的一定都实现。 本章内容 使用Docker镜像。 本文实操全部基于Ubuntu 20.04 一、使用Docker镜像 镜像&#xff08;image&#xff09;是Docker三大核心概念中最重要的&#xff0c;Docker运行容器前需要本地存在对应得…

在wsl下开发T113的主线linux(5)-构建ubi文件系统

接下来是构建文件系统&#xff0c;这里使用最新的buildroothttps://buildroot.org/download.htmlhttps://buildroot.org/download.html tar xf buildroot-2022.11.tar.gz cd buildroot-2022.11 make menuconfig 配置目标指令集类型 配置外部自定义编译器 配置生成文件系统类型…

数据结构和算法--算法与数据结构的概述、简单排序

目录 算法 算法概述 算法复杂度 数据结构 数据结构的概述 物理结构 逻辑结构 简单排序 1.选择排序 1.1算法描述 1.2算法实现 2冒泡排序 2.1算法描述 2.2算法实现 3插入排序 3.1算法描述 3.2算法实现 三种算法的比较 算法 算法概述 算法是一系列程序指令&am…

回溯算法题型

目录 一组合总和 二组合总和 三子集 四全排列 五解数独 一组合总和 题目描述&#xff1a; 找出所有相加之和为 n 的 k 个数的组合&#xff0c;且满足下列条件&#xff1a; 只使用数字1到9每个数字 最多使用一次 返回 所有可能的有效组合的列表 。该列表不能包含相同的组…

ArcGIS基础:提取道路中心线

本实验为对道路路面数据进行中心线提取 以路边两侧边界为准&#xff0c;运用等分的办法实现道路中心线提取&#xff0c;原始数据如下所示&#xff08;来源于网络&#xff09;。 道路顶端有一些圆弧段的部分&#xff0c;需要把其去除。 首先要做的是面转线操作&#xff0c;如下…

HashMap解读

1.简介 HashMap &#xff0c;是一种散列表&#xff0c;用于存储 key-value 键值对的数据结构&#xff0c;一般翻译为“哈希表”&#xff0c;提供平均时间复杂度为 O(1) 的、基于 key 级别的 get/put 等操作。 2.哈希表结构 哈希表结构为数组&#xff0c;链表和红黑树。如图 …

已解决+ FullyQualifiedErrorId : UnauthorizedAccess

已解决无法加载文件 E:\day_01\Scripts\activate.ps1&#xff0c;因为在此系统上禁止运行脚本。有关详细信息&#xff0c;请参阅 https:/go.microsoft.com/fwlink/?LinkID135170 中的about_Execution_Policies。 CategoryInfo: SecurityError: &#xff08;:&#xff09; [ ]…

Spring Bean的配置详解

目录 1.bean基础配置 例如&#xff1a;配置UserDaolmpl由Spring容器负责管理 2.Spring开发中主要是对Bean的配置&#xff0c; Bean的常用配置一览如下&#xff1a; 3.bean的别名配置 4.bean作用范围配置 5.bean的实例化 6.bean生命周期 7.Spring的get方法 8.Bean的延迟加载…

57. 数据增广 / 图像增广 代码实现

1. 图像增广 在对常用图像增广方法的探索时&#xff0c;我们将使用下面这个尺寸为400 x 500的图像作为示例。 从github上把img下载下来后&#xff0c;放到同一目录下&#xff1a; d2l.set_figsize() img d2l.Image.open(./img/cat1.jpg) d2l.plt.imshow(img);大多数图像增广…

数字通信系统和模拟通信系统的简单介绍

关于数字和模拟&#xff0c;比较形象的一个对比如下图所示。 模拟系统就好比传统的钟表&#xff0c;秒钟一直在走&#xff0c;也就是连续之意&#xff1b;而数字系统相当于数字表&#xff0c;“ &#xff1a;”的闪烁相当于二进制的 0 和 1&#xff0c;有离散之意。 模拟通信系…

a billion ways to grasp

https://blog.csdn.net/weixin_26752765/article/details/108132661 翻译自 https://darshanhegde.github.io/blog/2020/heuristics-for-robotic-grasping/ 讲述了各种抓取 https://rpal.cse.usf.edu/competition_iros2021/ Grasping is one of the fundamental subtask of a r…

ECCV 2022|DynamicDepth:动态场景下的多帧自监督深度估计

&#x1f3c6;前言&#xff1a;本文别名DynamicDepth (github),如本文的名字所示&#xff0c;本文着重处理的就是动态场景下的多帧自监督深度估计问题。因为MVS在动态场景下会失效&#xff0c;所以在动态区域的多帧深度并不可靠。现在的已有方法例如ManyDepth&#xff0c;利用t…

老王linux面试题汇总

1.统计一个网站的访问量&#xff0c;统计网站访问次数最多的前几名的IP地址。 2.取两个文件的相同和不同行 3.分别创建10个账号&#xff08;user1-user10&#xff09; 5.独立磁盘冗余阵列RAID O,1,5,6,10,01级别区别 5.1磁盘利用率 5.2最少几盘磁盘实现 5.3容错性&#xff0c;…

(十二)大白话对于VARCHAR这种变长字段,在磁盘上到底是如何存储的?

文章目录 1、一行数据在磁盘上存储的时候,包含哪些东西?2、变长字段在磁盘中是怎么存储的?3、存储在磁盘文件里的变长字段,为什么难以读取?4、引入变长字段的长度列表,解决一行数据的读取问题5、引入变长字段长度列表后,如何解决变长字段的读取问题?6、如果有多个变长字…

蒙特卡洛积分、重要性采样、低差异序列

渲染公式 渲染的目标在于计算周围环境的光线有多少从表面像素点反射到相机视口中。要计算总的反射光&#xff0c;每个入射方向的贡献&#xff0c;必须将他们在半球上相加&#xff1a; 为入射光线 与法线 的夹角,为方便计算可以使用法线向量和入射向量&#xff08;单位化&…

Linux|科普扫盲帖|配置网络软件源---阿里云镜像仓库服务使用(centos,Ubuntu)

前言&#xff1a; 部署搭建各种环境&#xff0c;例如&#xff0c;集群环境&#xff0c;编译环境&#xff0c;测试环境&#xff0c;桌面环境&#xff0c;lnmp环境等等以及修复各种各样的漏洞&#xff0c;基本是使用本地仓库就可以完成的&#xff0c;但本地仓库有一个比较致命的…

深入理解TDNN(Time Delay Neural Network)——兼谈x-vector网络结构

概述 TDNN&#xff08;Time Delay Neural Network&#xff0c;时延神经网络&#xff09;是用于处理序列数据的&#xff0c;比如&#xff1a;一段语音、一段文本将TDNN和统计池化&#xff08;Statistics Pooling&#xff09;结合起来&#xff0c;正如x-vector的网络结构&#x…

x86_64架构的VINS-fusion-GPU部署

x86_64架构的VINS-fusion-GPU部署 1. 环境配置&#xff08;Ubuntu 18.04&#xff09; &#xff08;0&#xff09;CUDA 10.2 安装 由于笔记本的GPU太老&#xff08;GeForce 840M&#xff09;&#xff0c;只能使用较低版本的 CUDA&#xff0c;但是也能有个好处就是能够同时兼顾…

Linux TCP 拥塞正反馈 bad case

前置知识&#xff0c;TCP thin stream&#xff0c;参见&#xff1a; 该文档中搜索 tcp_thin_linear_timeoutsTCP-thin-stream 看图说话&#xff1a; 参见 tcp_retransmit_timer 函数&#xff0c;着重看下面段落&#xff1a; if (sk->sk_state TCP_ESTABLISHED &&am…

视觉SLAM学习路线

导师让我了解SLAM&#xff0c;SLAM原本是比较小众的方向&#xff0c;最近自动驾驶火起来&#xff0c;做这个SLAM的人也多了&#xff0c;反过来也会推动机器人感知的发展。希望未来学成的时候&#xff0c;能赶上机器人大规模普及&#xff0c;就业一片蓝海。学SLAM方向跟motion p…