Java设计模式:一、六大设计原则-03:里氏替换原则
文章目录
- 一、定义:里氏替换原则
- 1.1 里氏替换原则
- 1.2 里氏替换原则的作用
- 二、模拟场景:里氏替换原则
- 三、违背方案:里氏替换原则
- 3.1 工程结构
- 3.2 储蓄卡和信用卡
- 3.2.1 储蓄卡
- 3.2.2 信用卡
- 3.3 单元测试
- 3.3.1 储蓄卡测试
- 3.3.2 信用卡测试
- 四、改善代码:里氏替换原则
- 4.1 工程结构
- 4.2 银行卡:储蓄卡和信用卡
- 4.2.1 抽象银行卡类
- 4.2.2 储蓄卡
- 4.2.2 信用卡
- 4.3 单元测试
- 4.3.1 里氏替换测试
- 4.3.2 信用卡测试
- 五、总结:里氏替换原则
一、定义:里氏替换原则
1.1 里氏替换原则
- 里氏替换原则:
Liskov Substitution Principle,LSP
。- 如果 S 是 T 的子类型,那么所有 T 类型的对象都可以在不破坏程序的情况下被 S 类型的对象替换。
- 简单来说:子类可以扩展父类的功能,但不能改变父类原有的功能。
- 也就是说:当子类继承父类时,除添加新的方法且完成新增功能外,尽量不要重写父类的方法。
- 子类可以实现父类的抽象方法,但不能覆盖父类的非抽象方法。
- 子类可以增加自己特有的方法。
- 当子类的方法重载父类的方法时,方法的前置条件(即方法的输入参数)要比父类的方法更宽松。
- 当子类的方法实现父类的方法(重写、重载或实现抽象方法)时,方法的后置条件(即方法的输出或返回值)要比父类的方法更严格或与父类的方法相等。
1.2 里氏替换原则的作用
- 里氏替换原则是实现开闭原则的重要方式之一。
- 解决了继承中重写父类造成的可复用性变差的问题。
- 是动作正确性的保证,即类的扩展不会给已有的系统引入新的错误,降低了代码出错的可能性。
- 加强程序的健壮性,同时变更时可以做到非常好的兼容性,提高程序的维护性、可扩展性,降低需求变更时引入的风险。
二、模拟场景:里氏替换原则
- 我们会使用各种类型的银行卡,例如储蓄卡、信用卡,还有一些其他特性的银行卡。
- 储蓄卡和信用卡都具备一定的消费功能,但又有一些不同。例如信用卡不宜提现,如果提现可能会产生高额的利息。
- 模拟场景:假设在构建银行系统时,储蓄卡是第一个类,信用卡是第二个类。
- 为了让信用卡可以使用储蓄卡的一些方法,选择由信用卡类继承储蓄卡类,讨论是否满足里氏替换原则产生的一些要点。
三、违背方案:里氏替换原则
- 储蓄卡和信用卡在使用功能上类似,都有支付、提现、还款、充值等功能,但有些许不同。
- 例如支付:储蓄卡做的是账户扣款动作,信用卡做的是生成贷款单动作。
3.1 工程结构
design-1.3-0
|——src|——main|--java|--com.lino.design|--CashCard.java|--CreditCard.java|——test|--java|--com.lino.design.test|--ApiTest.java
3.2 储蓄卡和信用卡
3.2.1 储蓄卡
CashCard.java
package com.lino.design;import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;/*** @description: 模拟储蓄卡功能*/
public class CashCard {private Logger logger = LoggerFactory.getLogger(CashCard.class);/*** 提现** @param orderId 单号* @param amount 金额* @return 状态码 0000成功、0001失败、0002重复*/public String withdrawal(String orderId, BigDecimal amount) {// 模拟支付成功logger.info("提现成功,单号:{} 金额:{}", orderId, amount);return "0000";}/*** 储值** @param orderId 单号* @param amount 金额* @return 状态码 0000成功、0001失败、0002重复*/public String recharge(String orderId, BigDecimal amount) {// 模拟充值成功logger.info("储值成功,单号:{} 金额:{}", orderId, amount);return "0000";}/*** 交易流水查询** @return 交易流水*/public List<String> tradeFlow() {logger.info("交易流水查询成功");List<String> tradeList = new ArrayList<>();tradeList.add("100001,100.00");tradeList.add("100001,80.00");tradeList.add("100001,76.50");tradeList.add("100001,126.00");return tradeList;}
}
- 在储蓄卡的功能实现中包括了三个方法:提现、储蓄、交易流水查询,这些是模拟储蓄卡的基本功能。
3.2.2 信用卡
CreditCard.java
package com.lino.design;import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.math.BigDecimal;
import java.util.List;/*** @description: 模拟信用卡功能*/
public class CreditCard extends CashCard {private Logger logger = LoggerFactory.getLogger(CreditCard.class);@Overridepublic String withdrawal(String orderId, BigDecimal amount) {// 校验if (amount.compareTo(new BigDecimal(1000)) >= 0) {logger.info("贷款金额校验(限额1000元),单号:{} 金额:{}", orderId, amount);return "0001";}// 模拟生成贷款单logger.info("生成贷款单,单号:{} 金额:{}", orderId, amount);// 模拟支付成功logger.info("贷款成功,单号:{} 金额:{}", orderId, amount);return "0000";}@Overridepublic String recharge(String orderId, BigDecimal amount) {// 模拟生成还款单logger.info("生成还款单,单号:{} 金额:{}", orderId, amount);// 模拟还款成功logger.info("还款成功,单号:{} 金额:{}", orderId, amount);return "0000";}@Overridepublic List<String> tradeFlow() {return super.tradeFlow();}}
- 信用卡的功能实现是在继承了储蓄卡类后,进行方法重学:支付
withdrawal()
、还款recharge()
。交易流水可以复用,不用重写这个类。 - 这种继承父类方式的优点是复用了父类的核心功能逻辑,但是也破坏了原有的方法。
- 此时继承父类实现的信用卡类并不满足里氏替换原则,也就是说,此时的子类不能承担原父类的功能,直接给储蓄卡使用。
3.3 单元测试
3.3.1 储蓄卡测试
ApiTest.java
@Test
public void test_CashCard() {CashCard cashCard = new CashCard();// 提现cashCard.withdrawal("100001", new BigDecimal(100));// 储蓄cashCard.recharge("100001", new BigDecimal(100));// 交易流水List<String> tradeFlow = cashCard.tradeFlow();logger.info("查询交易流水:{}", JSON.toJSONString(tradeFlow));
}
测试结果
10:58:28.027 [main] INFO com.lino.design.CashCard - 提现成功,单号:100001 金额:100
10:58:28.031 [main] INFO com.lino.design.CashCard - 储值成功,单号:100001 金额:100
10:58:28.031 [main] INFO com.lino.design.CashCard - 交易流水查询成功
10:58:28.169 [main] INFO com.lino.design.test.ApiTest - 查询交易流水:["100001,100.00","100001,80.00","100001,76.50","100001,126.00"]
3.3.2 信用卡测试
ApiTest.java
@Test
public void test_CreditCard() {CreditCard creditCard = new CreditCard();// 支付creditCard.withdrawal("100001", new BigDecimal(100));// 还款creditCard.recharge("100001", new BigDecimal(100));// 交易流水List<String> tradeFlow = creditCard.tradeFlow();logger.info("查询交易流水:{}", JSON.toJSONString(tradeFlow));
}
测试结果
10:59:23.970 [main] INFO com.lino.design.CreditCard - 生成贷款单,单号:100001 金额:100
10:59:23.970 [main] INFO com.lino.design.CreditCard - 贷款成功,单号:100001 金额:100
10:59:23.970 [main] INFO com.lino.design.CreditCard - 生成还款单,单号:100001 金额:100
10:59:23.970 [main] INFO com.lino.design.CreditCard - 还款成功,单号:100001 金额:100
10:59:23.970 [main] INFO com.lino.design.CashCard - 交易流水查询成功
10:59:24.003 [main] INFO com.lino.design.test.ApiTest - 查询交易流水:["100001,100.00","100001,80.00","100001,76.50","100001,126.00"]
四、改善代码:里氏替换原则
4.1 工程结构
design-1.3-1
|——src|——main|--java|--com.lino.design|--BandCard.java|--CashCard.java|--CreditCard.java|——test|--java|--com.lino.design.test|--ApiTest.java
4.2 银行卡:储蓄卡和信用卡
- 储蓄卡和信用卡在功能使用上有些许类似,在实际的开发过程中也有很多共同可复用的属性及逻辑。
- 实现这样的类的最好方式是提取出一个抽象类,由抽象类定义所有卡的共用核心属性、逻辑,把卡的支付和还款等动作抽象成正向和逆向操作。
4.2.1 抽象银行卡类
BandCard.java
package com.lino.design;import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;/*** @description: 银行卡*/
public abstract class BandCard {private Logger logger = LoggerFactory.getLogger(BandCard.class);/*** 卡号*/private String cardNo;/*** 开卡时间*/private String cardDate;public BandCard(String cardNo, String cardDate) {this.cardNo = cardNo;this.cardDate = cardDate;}/*** 金额判断规则** @param amount 金额* @return 是否符合规则*/abstract boolean rule(BigDecimal amount);/*** 正向入账:+钱** @param orderId 单号* @param amount 金额* @return 状态码*/public String positive(String orderId, BigDecimal amount) {// 入款成功,存款、还款logger.info("卡号{} 入款成功:单号:{} 金额:{}", cardNo, orderId, amount);return "0000";}/*** 逆向入账:-钱** @param orderId 单号* @param amount 金额* @return 状态码*/public String negative(String orderId, BigDecimal amount) {// 出款成功,支付、贷款logger.info("卡号{} 出款成功:单号:{} 金额:{}", cardNo, orderId, amount);return "0000";}/*** 交易流水查询** @return 交易流水*/public List<String> tradeFlow() {logger.info("交易流水查询成功");List<String> tradeList = new ArrayList<>();tradeList.add("100001,100.00");tradeList.add("100001,80.00");tradeList.add("100001,76.50");tradeList.add("100001,126.00");return tradeList;}public String getCardNo() {return cardNo;}public String getCardDate() {return cardDate;}
}
- 在抽象银行卡类中,提供了基本的卡属性,包括卡号、开卡时间及三个核心方法。
- 正向入账,加钱;逆向入账,减钱;交易流水查询;
4.2.2 储蓄卡
CashCard.java
package com.lino.design;import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.math.BigDecimal;/*** @description: 模拟储值卡功能*/
public class CashCard extends BandCard {private Logger logger = LoggerFactory.getLogger(CashCard.class);public CashCard(String cardNo, String cardDate) {super(cardNo, cardDate);}@Overrideboolean rule(BigDecimal amount) {return true;}/*** 提现** @param orderId 单号* @param amount 金额* @return 状态码 0000成功、0001失败、0002重复*/public String withdrawal(String orderId, BigDecimal amount) {// 模拟支付成功logger.info("提现成功,单号:{} 金额:{}", orderId, amount);return super.negative(orderId, amount);}/*** 储值** @param orderId 单号* @param amount 金额* @return 状态码 0000成功、0001失败、0002重复*/public String recharge(String orderId, BigDecimal amount) {// 模拟充值成功logger.info("储值成功,单号:{} 金额:{}", orderId, amount);return super.positive(orderId, amount);}/*** 风险校验** @param cardNo 卡号* @param orderId 单号* @param amount 金额* @return 状态码*/public boolean checkRisk(String cardNo, String orderId, BigDecimal amount) {// 模拟风控校验logger.info("风控校验:卡号:{} 单号:{} 金额:{}", cardNo, orderId, amount);return true;}
}
- 储蓄卡类中继承抽象银行卡父类
BandCard
,实现的核心功能包括规则过滤rule
、提现withdrawal
、储蓄recharge
和新增的扩展方法,即风控校验checkRisk
。 - 这样的实现方式满足了里氏替换的基本原则,即实现抽象类的抽象方法,又没有破坏父类中的原有方法。
4.2.2 信用卡
CreditCard.java
package com.lino.design;import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.math.BigDecimal;/*** @description: 信用卡*/
public class CreditCard extends CashCard {private Logger logger = LoggerFactory.getLogger(CreditCard.class);public CreditCard(String cardNo, String cardDate) {super(cardNo, cardDate);}boolean rule2(BigDecimal amount) {return amount.compareTo(new BigDecimal(1000)) <= 0;}/*** 提现,信用卡贷款** @param orderId 单号* @param amount 金额* @return 状态码*/public String loan(String orderId, BigDecimal amount) {boolean rule = rule2(amount);// 校验if (!rule) {logger.info("生成贷款单失败,金额超限。单号:{} 金额:{}", orderId, amount);return "0001";}// 模拟生成贷款单logger.info("生成贷款单,单号:{} 金额:{}", orderId, amount);// 模拟支付成功logger.info("贷款成功,单号:{} 金额:{}", orderId, amount);return super.negative(orderId, amount);}/*** 还款,信用卡还款** @param orderId 单号* @param amount 金额* @return 状态码*/public String repayment(String orderId, BigDecimal amount) {// 模拟生成还款单logger.info("生成还款单,单号:{} 金额:{}", orderId, amount);// 模拟还款成功logger.info("还款成功,单号:{} 金额:{}", orderId, amount);return super.positive(orderId, amount);}
}
- 信用卡类在继承父类后,使用了公用的属性,即卡号
cardNo
、开卡时间cardDate
,同时新增了符合信用卡功能的新方法,即贷款loan
、还款repayment
,并在两个方法中都使用了抽象类的核心功能。 - 另外,关于储蓄卡中的规则校验方法,新增了自己的规则方法
rule2
,并没有破坏储蓄卡中的校验方法。 - 以上的实现方式都是在遵循里氏替换原则下完成的,子类随时可以替换储蓄卡类。
4.3 单元测试
4.3.1 里氏替换测试
ApiTest.java
@Test
public void test_bandCard() {logger.info("里氏替换前,CashCard类:");CashCard bandCard = new CashCard("6214567800989876", "2022-12-14");// 提现bandCard.withdrawal("100001", new BigDecimal(100));// 储蓄bandCard.recharge("100001", new BigDecimal(100));logger.info("里氏替换后,CreditCard类:");CashCard creditCard = new CreditCard("6214567800989876", "2022-12-14");// 提现creditCard.withdrawal("100001", new BigDecimal(1000000));// 储蓄creditCard.recharge("100001", new BigDecimal(100));
}
测试结果
11:16:03.817 [main] INFO com.lino.design.test.ApiTest - 里氏替换前,CashCard类:
11:16:03.817 [main] INFO com.lino.design.CashCard - 提现成功,单号:100001 金额:100
11:16:03.817 [main] INFO com.lino.design.BandCard - 卡号6214567800989876 出款成功:单号:100001 金额:100
11:16:03.817 [main] INFO com.lino.design.CashCard - 储值成功,单号:100001 金额:100
11:16:03.817 [main] INFO com.lino.design.BandCard - 卡号6214567800989876 入款成功:单号:100001 金额:100
11:16:03.817 [main] INFO com.lino.design.test.ApiTest - 里氏替换后,CreditCard类:
11:16:03.817 [main] INFO com.lino.design.CashCard - 提现成功,单号:100001 金额:1000000
11:16:03.817 [main] INFO com.lino.design.BandCard - 卡号6214567800989876 出款成功:单号:100001 金额:1000000
11:16:03.817 [main] INFO com.lino.design.CashCard - 储值成功,单号:100001 金额:100
11:16:03.817 [main] INFO com.lino.design.BandCard - 卡号6214567800989876 入款成功:单号:100001 金额:100
4.3.2 信用卡测试
ApiTest.java
@Test
public void test_CreditCard() {CreditCard creditCard = new CreditCard("6214567800989876", "2022-12-14");// 支付,贷款creditCard.loan("100001", new BigDecimal(100));// 还款creditCard.repayment("100001", new BigDecimal(100));
}
测试结果
11:13:03.042 [main] INFO com.lino.design.CreditCard - 生成贷款单,单号:100001 金额:100
11:13:03.042 [main] INFO com.lino.design.CreditCard - 贷款成功,单号:100001 金额:100
11:13:03.042 [main] INFO com.lino.design.BandCard - 卡号6214567800989876 出款成功:单号:100001 金额:100
11:13:03.042 [main] INFO com.lino.design.CreditCard - 生成还款单,单号:100001 金额:100
11:13:03.042 [main] INFO com.lino.design.CreditCard - 还款成功,单号:100001 金额:100
11:13:03.042 [main] INFO com.lino.design.BandCard - 卡号6214567800989876 入款成功:单号:100001 金额:100
- 通过以上的测试结果可以看到,储蓄卡功能正常,继承储蓄卡实现的信用卡功能也正常。
- 同时,原有储蓄卡类的功能可以由信用卡类支持,即
CashCard creditCard = new CreditCard()
。
五、总结:里氏替换原则
- 继承作为面向对象的重要特征,虽然给程序开发带来了非常大的便利,但也引入了一些弊端。
- 继承的开发方式会给代码带来侵入性,可移植能力降低,类之间的耦合度较高。
- 当对父类修改时,就要考虑一整套子类的实现是否由风险,测试成本较高。
- 里氏替换原则的目的是使用约定的方式,让使用继承后的代码具备良好的扩展性和兼容性。
- 在日常开发中使用继承的地方并不多,在代码规范中也不会允许多层继承,尤其是一些核心服务的扩展。
- 而继承多数用在系统架构初期定义好的逻辑上或抽象出的核心功能里。
- 如果使用了继承,就一定要遵从里氏替换原则,否则会让代码出现问题的概率变得更大。
相关文章:
Java设计模式:一、六大设计原则-03:里氏替换原则
文章目录 一、定义:里氏替换原则1.1 里氏替换原则1.2 里氏替换原则的作用 二、模拟场景:里氏替换原则三、违背方案:里氏替换原则3.1 工程结构3.2 储蓄卡和信用卡3.2.1 储蓄卡3.2.2 信用卡 3.3 单元测试3.3.1 储蓄卡测试3.3.2 信用卡测试 四、…...
jmeter 固定定时器
固定定时器(Constant Timer)是一个定时器元件,可以在线程组中的每个线程之间添加固定的延迟时间。固定定时器会对每个线程的执行进行一定的暂停。 聊一下和线程组中的调度器对线程组执行时长的影响: 相同: 都会影响线…...
【微服务部署】07-调用链追踪
文章目录 集成SkyWalking实现调用链追踪1. SkyWalking架构图2. 代码集成SkyWalking 集成SkyWalking实现调用链追踪 1. SkyWalking架构图 Receiver是SkyWalking的入口,支持gRPC和HTTP协议。 SkyWalking内部有分析和查询两个部分 存储方面SkyWalking支持Elasticsearc…...
【C++入门】命名空间、缺省参数、函数重载、引用、内联函数
👻内容专栏: C/C编程 🐨本文概括: C入门学习必备语法 🐼本文作者: 阿四啊 🐸发布时间:2023.9.3 前言 C是在C的基础之上,容纳进去了面向对象编程思想,并增加…...
c++ 学习之 构造函数的使用规则
上规则 // 默认情况下,c 编译器至少给一个类添加三个函数 //1.默认构造函数(无参,函数体为空) //2.默认析构函数 (无参 ,函数体为空) //3.默认拷贝函数,对其属性进行值拷贝 //构…...
C++操作符重载的注意事项
关于C操作符重载,可以用类内的成员运算符重载或友元函数。但是注意两个不能同时出现,不然编译出错。 #include<iostream> using namespace std; class Complex{public:Complex(int r0,int i0){real r;imag i;}//#if 0Complex operator(Complex …...
10 | Spark 查找每个单词的最大行号
假设你有一个包含文本行号和文本内容的RDD,现在你想找出每个单词出现在哪些行,并计算它们出现的最大行号。 需求是从包含文本行号和文本内容的RDD中找出每个单词出现在哪些行,并计算它们出现的最大行号。 具体需求如下: 数据输入: 代码从一个包含文本行号和文本内容的RD…...
CRE66365
CRE66365是一款高度集成的电流模式PWM控制IC,为高性能、低待机功耗和低成本的隔离型反激转换器。在正常负载条件下,AC输入高电压下工作在QR模式。为了最大限度地减少开关损耗,QR 模式下的最大开关频率被内部限制为 77kHz。当负载较低时&#…...
React hook 10种常见 Hook
React Hook是什么? React官网是这么介绍的: Hook 是 React 16.8 的新增特性。它可以让你在不编写 class 的情况下使用 state 以及其他的 React 特性。 完全可选的 你无需重写任何已有代码就可以在一些组件中尝试 Hook。但是如果你不想,你不…...
图文详解PhPStudy安装教程
版权声明 本文原创作者:谷哥的小弟作者博客地址:http://blog.csdn.net/lfdfhl 官方下载 请在PhPStudy官方网站下载安装文件,官方链接如下:https://m.xp.cn/linux.html;图示如下: 请下载PhPStudy安装文件…...
stable diffusion实践操作-hypernetworks
系列文章目录 本文专门开一节写hypernetworks的内容,在看之前,可以同步关注: stable diffusion实践操作 提示:写完文章后,目录可以自动生成,如何生成可参考右边的帮助文档 文章目录 系列文章目录前言一、h…...
Win10搭建VisualSvn Server
Win10搭建VisualSvn Server 目录 Win10搭建VisualSvn Server一、下载VisualSvn Server安装包二、安装VisualSvn Server三、配置和使用VisualSVN Server四、添加用户及权限设定方法五、创建目录及配置权限 1、服务端:有集成了Subversion和Apache、安装使用非常简单且…...
Golang网络编程
Golang网络编程 网络编程简介网络编程协议网络分层模型TCP/IP协议什么是DNS套接字(Socket)客户端服务器模型TCP/UDP的区别HTTP协议会话sessionCookiehttpsHTTP请求格式HTTP响应格式http头信息http请求头信息http响应头信息HTTP状态码http内容类型和内容…...
详解vue3中ref和reactive用法和区别
vue3中ref和reactive区别 1、前言2、基本用法2.1 ref2.2 reactive 3、ref和reactive定义数组对比3.1 ref定义数组3.1 reactive定义数组 4、ref 和reactive的区别 1、前言 ref和reactive是Vue3中用来实现数据响应式的API,一般情况下,ref定义基本数据类型…...
QML与C++的交互操作
QML旨在通过C 代码轻松扩展。Qt QML模块中的类使QML对象能够从C 加载和操作,QML引擎与Qt元对象系统集成的本质使得C 功能可以直接从QML调用。这允许开发混合应用程序,这些应用程序是通过混合使用QML,JavaScript和C 代码实现的。除了从QML访问…...
Java_理解方法调用
理解方法调用 首先什么是隐式参数 --->隐式参数是调用该方法的对象本身。 接下来方法的名称和参数列表被称为方法的签名(signature)。在Java中,方法的签名由方法的名称和参数列表组成,用于唯一标识一个方法。返回类型不是签名的…...
Mysql 性能分析(慢日志、profiling、explain)、读写分离(主从架构)、分库分表(垂直分库、垂直分表、水平分表)
查看系统性能参数 一条sql查询语句在执行前,需要确定查询执行计划,如果存在多种执行计划的话,mysql会计算每个执行计划所需要的成本,从中选择 成本最小的一个作为最终执行的执行计划 想要查看某条sql语句的查询成本,可…...
获取Linux内核源码
在嵌入式平台上做Linux开发的时候,我们用的kernel都是芯片厂家移植到自家平台上的,但是最初的原生Linux内核的源码是从哪里来的呢?下面我们介绍一下怎么获取原生的Linux源码。 从Linux社区获取内核kernel源码 Linux社区的官方网站是 https:…...
【Maven教程】(四)坐标与依赖:坐标概念,依赖配置、范围、传递性和最佳实践 ~
Maven 坐标与依赖 1️⃣ 什么是Maven 坐标2️⃣ 坐标详解3️⃣ 依赖的配置4️⃣ 依赖范围5️⃣ 传递性依赖6️⃣ 依赖调解7️⃣ 可选依赖8️⃣ 最佳实践8.1 排除依赖8.2 归类依赖8.3 优化依赖 🌾 总结 正如前面文章所述,Maven 的一大功能是管理项目依赖…...
Java“牵手”京东店铺所有商品API接口数据,通过店铺ID获取整店商品详情数据,京东店铺所有商品API申请指南
京东平台店铺所有商品数据接口是开放平台提供的一种API接口,通过调用API接口,开发者可以获取京东整店的商品的标题、价格、库存、月销量、总销量、库存、详情描述、图片、价格信息等详细信息 。 获取店铺所有商品接口API是一种用于获取电商平台上商品详…...
TuyaOS开发学习笔记(1)——NB-IoT开发搭建环境、编译烧写(MT2625)
一、搭建环境 1.1 官方资料 TuyaOS 1.2 安装VMware 官网下载:https://customerconnect.vmware.com/en/downloads/info/slug/desktop_end_user_computing/vmware_workstation_pro/16_0 百度网盘:https://pan.baidu.com/s/1oN7H81GV0g6cD9zsydg6vg 提取…...
Css 将div设置透明度,并向上移50px,盖住上面的元素一部分
可以使用CSS中的opacity和position属性来实现。 首先,将div的opacity属性设置为小于1的值,比如0.5,这样就可以设置透明度了。其次,将div的position设置为relative,然后再将它向上移动50px,即可盖住上面的元…...
HTTPS安全通信和SSL Pinning
随着互联网的迅速发展,网络通信安全问题日益凸显。在这一背景下,HTTPS作为一种加密通信协议得到了广泛应用,以保障用户的数据隐私和信息安全。本文将介绍HTTPS的基本原理、发展历程,以及与之相关的中间人攻击和防护方法。 1. HTT…...
PHP自己的框架PDO数据表前缀、alias、model、table、join方法实现(完善篇九--结束)
一、实现功能,数据表前缀、alias、model、table、join方法实现 二、表前缀实现 1、config.php增加表前缀 DB_PEX>fa_,//数据库前缀 2、增加表前缀方法function.php function model($table){$modelnew ModelBase($table,config("DB_PEX"));return $m…...
华为OD:敏感字段加密
题目描述: 给定一个由多个命令字组成的命令字符串: 1、字符串长度小于等于127字节,只包含大小写字母,数字,下划线和偶数个双引号; 2、命令字之间以一个或多个下划线_进行分割; 3、可以通过两个双引号”"来标识包含下划线…...
IDEA新建SpringBoot项目时启动编译报错:Error:java: 无效的源发行版: 17
文章目录 原因检查解决步骤修改jdk修改SpringBoot版本 原因 出现这种错误的原因可能是: 本机默认使用(编译)的jdk与该项目所使用的jdk版本不同。 jdk版本不适用于这个Idea,很典型的一个例子就是使用的Idea是2020的,而…...
【云原生进阶之PaaS中间件】第一章Redis-2.3.3集群模式
1 集群模式 Redis集群是一个提供在多个Redis节点之间共享数据的程序集。它并不像Redis主从复制模式那样只提供一个master节点提供写服务,而是会提供多个master节点提供写服务,每个master节点中存储的数据都不一样,这些数据通过数据分片的方式被自动分割到不同的master节点上…...
游戏发行商能够提供什么服务?
游戏发行商可以为游戏开发者提供广泛的服务,以帮助他们将游戏成功地引入市场并取得更好的业绩。以下是游戏发行商可能提供的一些服务: 市场营销和宣传:发行商通常具有丰富的市场营销经验,可以制定并执行有效的宣传和营销策略。他们…...
Linux 多进程解决客户端与服务器端通信
写一个服务器端用多进程处理并发,使两个以上的客户端可以同时连接服务器端得到响应。每当接受一个新的连接就fork产生一个子进程,让子进程去处理这个连接,父进程只用来接受连接。 与多线程相比的不同点:多线程如果其中一个线程操…...
Scala的模式匹配
Scala的模式匹配 Scala 中的模式匹配类似于Java 中的 switch 语法:下面是java中switch代码: int i 10 switch (i) {case 10 :System.out.println("10");break; case 20 :System.out.println("20");break; default :System.out.pr…...
frontpg做网站好吗/seo有哪些作用
在hexo根目录下 touch hexo-pubish.sh vi hexo-pubish.sh 写入 #!/usr/bin/env sh hexo clean hexo g hexo d 修改配置文件 加入 deployCommand: ./hexo-publish.sh 修改sh文件的执行权限 chmod x hexo-publish.sh 修改后再次执行...
wordpress站点导航页面url/百度品牌广告
java使用ResourceBundle读取配置文件2019-08-22 23:53:45.0使用 ResourceBudle 的静态方法 getBundle() 来获得 ResourceBudle 实例,但是第一个参数不能写成文件的路径,而要按照包名类名的方式写。例如:需要读取的文件为Resource.properties&…...
网站建设安全需求/百度安装免费下载
【广东最美的山】:肇庆鼎湖山点评:鼎湖山自然环境、历史沉淀、规模、各方面综合条件较好,最能代表广东山的美。【广东最美的峡谷】:乳源大峡谷点评:广东最大的峡谷,对驴友来说,最吸引人的是&…...
深圳做网站设计公司/搜易网提供的技术服务
C语言acm竞赛习题集锦目录数塔问题............................2并查集类问题........................4递推类问题..........................9动态规划系列........................10概率类题型..........................13组合数学类题型......................15贪心策略…...
wordpress备案号不显示/百度校招
模板介绍 精美PPT模板设计,布系卡通创意风格六一儿童节PPT模板。一套节日PPT幻灯片模板,内含青色,红色多种配色,精美风格设计,动态播放效果,精美实用。 一份设计精美的PPT模板,可以让你在汇报演讲时脱颖而…...
推荐昆明做网站建设/境外电商有哪些平台
Python是一种广泛使用的高级编程语言,因其简单易学、灵活性强和广泛的应用领域而闻名。在开始Python编程之前,首先需要在您的计算机上安装Python解释器。本教程将为您提供详细的Python下载和安装步骤,以帮助您顺利安装Python并开始编写Python…...