java面试设计模式篇
面试专题-设计模式
前言
在平时的开发中,涉及到设计模式的有两块内容,第一个是我们平时使用的框架(比如spring、mybatis等),第二个是我们自己开发业务使用的设计模式。
面试官一般比较关心的是你在开发过程中,有没有使用过设计模式,或者你在简历上写了关于设计模式的描述,那么这样我们就需要重点关心自己开发中用过的设计模式。
在平时的业务开发中,其实真正使用设计模式的场景并不多,虽然设计号称有23种之多(不同的纬度可能会更多),但是在项目最常使用的也就几种而已,在面试的过程中,我们主要介绍一种或两种就可以,重点要说的是:在什么业务场景下使用了设计模式,什么设计模式?
这次面试部分,我们主要介绍三种设计模式:
-
工厂方法模式(简单工厂、工厂方法、抽象工厂)
-
策略模式
-
责任链模式
1 工厂方法模式
1.1 概述
需求:设计一个咖啡店点餐系统。
设计一个咖啡类(Coffee),并定义其两个子类(美式咖啡【AmericanCoffee】和拿铁咖啡【LatteCoffee】);再设计一个咖啡店类(CoffeeStore),咖啡店具有点咖啡的功能。
具体类的设计如下:
1.类图中的符号
+:表示public
-:表示private
#:表示protected
2.泛化关系(继承)用带空心三角箭头的实线来表示
3.依赖关系使用带箭头的虚线来表示
package com.kjz.factory.simple;
public class CoffeeStore {
public static void main(String[] args) {Coffee coffee = orderCoffee("latte");System.out.println(coffee.getName());}
public static Coffee orderCoffee(String type){Coffee coffee = null;if("american".equals(type)){coffee = new AmericanCoffee();}else if ("latte".equals(type)){coffee = new LatteCoffee();}
//添加配料coffee.addMilk();coffee.addSuqar();return coffee;}
}
在java中,万物皆对象,这些对象都需要创建,如果创建的时候直接new该对象,就会对该对象耦合严重,假如我们要更换对象,所有new对象的地方都需要修改一遍,这显然违背了软件设计的开闭原则。如果我们使用工厂来生产对象,我们就只和工厂打交道就可以了,彻底和对象解耦,如果要更换对象,直接在工厂里更换该对象即可,达到了与对象解耦的目的;所以说,工厂模式最大的优点就是:解耦。
开闭原则:对扩展开放,对修改关闭。在程序需要进行拓展的时候,不能去修改原有的代码,实现一个热插拔的效果。简言之,是为了使程序的扩展性好,易于维护和升级。
三种工厂
-
简单工厂模式
-
工厂方法模式
-
抽象工厂模式
1.2 简单工厂模式
简单工厂不是一种设计模式,反而比较像是一种编程习惯。
1.2.1 结构
简单工厂包含如下角色:
-
抽象产品 :定义了产品的规范,描述了产品的主要特性和功能。
-
具体产品 :实现或者继承抽象产品的子类
-
具体工厂 :提供了创建产品的方法,调用者通过该方法来获取产品。
1.2.2 实现
现在使用简单工厂对上面案例进行改进,类图如下:
工厂类代码如下:
public class SimpleCoffeeFactory {
public Coffee createCoffee(String type) {Coffee coffee = null;if("americano".equals(type)) {coffee = new AmericanoCoffee();} else if("latte".equals(type)) {coffee = new LatteCoffee();}return coffee;}
}
咖啡店
package com.kjz.factory.simple;
public class CoffeeStore {
public Coffee orderCoffee(String type){//通过工厂获得对象,不需要知道对象实现的细节SimpleCoffeeFactory factory = new SimpleCoffeeFactory();Coffee coffee = factory.createCoffee(type);//添加配料coffee.addMilk();coffee.addSuqar();return coffee;}
}
工厂(factory)处理创建对象的细节,一旦有了SimpleCoffeeFactory,CoffeeStore类中的orderCoffee()就变成此对象的客户,后期如果需要Coffee对象直接从工厂中获取即可。这样也就解除了和Coffee实现类的耦合,同时又产生了新的耦合,CoffeeStore对象和SimpleCoffeeFactory工厂对象的耦合,工厂对象和商品对象的耦合。
后期如果再加新品种的咖啡,我们势必要需求修改SimpleCoffeeFactory的代码,违反了开闭原则。工厂类的客户端可能有很多,比如创建美团外卖等,这样只需要修改工厂类的代码,省去其他的修改操作。
1.2.3 优缺点
优点:
封装了创建对象的过程,可以通过参数直接获取对象。把对象的创建和业务逻辑层分开,这样以后就避免了修改客户代码,如果要实现新产品直接修改工厂类,而不需要在原代码中修改,这样就降低了客户代码修改的可能性,更加容易扩展。
缺点:
增加新产品时还是需要修改工厂类的代码,违背了“开闭原则”。
1.2.4 扩展
静态工厂
在开发中也有一部分人将工厂类中的创建对象的功能定义为静态的,这个就是静态工厂模式,它也不是23种设计模式中的。代码如下:
public class SimpleCoffeeFactory {
public static Coffee createCoffee(String type) {Coffee coffee = null;if("americano".equals(type)) {coffee = new AmericanoCoffee();} else if("latte".equals(type)) {coffee = new LatteCoffee();}return coffe;}
}
1.3 工厂方法模式
针对上例中的缺点,使用工厂方法模式就可以完美的解决,完全遵循开闭原则。
1.3.1 概念
定义一个用于创建对象的接口,让子类决定实例化哪个产品类对象。工厂方法使一个产品类的实例化延迟到其工厂的子类。
1.3.2 结构
工厂方法模式的主要角色:
-
抽象工厂(Abstract Factory):提供了创建产品的接口,调用者通过它访问具体工厂的工厂方法来创建产品。
-
具体工厂(ConcreteFactory):主要是实现抽象工厂中的抽象方法,完成具体产品的创建。
-
抽象产品(Product):定义了产品的规范,描述了产品的主要特性和功能。
-
具体产品(ConcreteProduct):实现了抽象产品角色所定义的接口,由具体工厂来创建,它同具体工厂之间一一对应。
1.3.3 实现
使用工厂方法模式对上例进行改进,类图如下:
流程:
代码如下:
抽象工厂:
public interface CoffeeFactory {
Coffee createCoffee();
}
具体工厂:
public class LatteCoffeeFactory implements CoffeeFactory {
public Coffee createCoffee() {return new LatteCoffee();}
}
public class AmericanCoffeeFactory implements CoffeeFactory {
public Coffee createCoffee() {return new AmericanCoffee();}
}
咖啡店类:
public class CoffeeStore {
private CoffeeFactory factory;
public CoffeeStore(CoffeeFactory factory) {this.factory = factory;}
public Coffee orderCoffee(String type) {Coffee coffee = factory.createCoffee();coffee.addMilk();coffee.addsugar();return coffee;}
}
从以上的编写的代码可以看到,要增加产品类时也要相应地增加工厂类,不需要修改工厂类的代码了,这样就解决了简单工厂模式的缺点。
工厂方法模式是简单工厂模式的进一步抽象。由于使用了多态性,工厂方法模式保持了简单工厂模式的优点,而且克服了它的缺点。
1.3.4 优缺点
优点:
-
用户只需要知道具体工厂的名称就可得到所要的产品,无须知道产品的具体创建过程;
-
在系统增加新的产品时只需要添加具体产品类和对应的具体工厂类,无须对原工厂进行任何修改,满足开闭原则;
缺点:
-
每增加一个产品就要增加一个具体产品类和一个对应的具体工厂类,这增加了系统的复杂度。
1.4 抽象工厂模式
前面介绍的工厂方法模式中考虑的是一类产品的生产,如畜牧场只养动物、电视机厂只生产电视机、传智播客只培养计算机软件专业的学生等。
这些工厂只生产同种类产品,同种类产品称为同等级产品,也就是说:工厂方法模式只考虑生产同等级的产品,但是在现实生活中许多工厂是综合型的工厂,能生产多等级(种类) 的产品,如电器厂既生产电视机又生产洗衣机或空调,大学既有软件专业又有生物专业等。
本节要介绍的抽象工厂模式将考虑多等级产品的生产,将同一个具体工厂所生产的位于不同等级的一组产品称为一个产品族,下图所示
-
产品族:一个品牌下面的所有产品;例如华为下面的电脑、手机称为华为的产品族;
-
产品等级:多个品牌下面的同种产品;例如华为和小米都有手机电脑为一个产品等级;
1.4.1 概念
是一种为访问类提供一个创建一组相关或相互依赖对象的接口,且访问类无须指定所要产品的具体类就能得到同族的不同等级的产品的模式结构。
抽象工厂模式是工厂方法模式的升级版本,工厂方法模式只生产一个等级的产品,而抽象工厂模式可生产多个等级的产品。
一个超级工厂创建其他工厂。该超级工厂又称为其他工厂的工厂
1.4.2 结构
抽象工厂模式的主要角色如下:
-
抽象工厂(Abstract Factory):提供了创建产品的接口,它包含多个创建产品的方法,可以创建多个不同等级的产品。
-
具体工厂(Concrete Factory):主要是实现抽象工厂中的多个抽象方法,完成具体产品的创建。
-
抽象产品(Product):定义了产品的规范,描述了产品的主要特性和功能,抽象工厂模式有多个抽象产品。
-
具体产品(ConcreteProduct):实现了抽象产品角色所定义的接口,由具体工厂来创建,它 同具体工厂之间是多对一的关系。
1.4.3 实现
现咖啡店业务发生改变,不仅要生产咖啡还要生产甜点
-
同一个产品等级(产品分类)
-
咖啡:拿铁咖啡、美式咖啡
-
甜点:提拉米苏、抹茶慕斯
-
-
同一个风味,就是同一个产品族(相当于同一个品牌)
-
美式风味:美式咖啡、抹茶慕斯
-
意大利风味:拿铁咖啡、提拉米苏
-
要是按照工厂方法模式,需要定义提拉米苏类、抹茶慕斯类、提拉米苏工厂、抹茶慕斯工厂、甜点工厂类,很容易发生类爆炸情况。
所以这个案例可以使用抽象工厂模式实现。类图如下:
实现关系使用带空心三角箭头的虚线来表示
整体调用思路:
1.4.4 优缺点
优点:
当一个产品族中的多个对象被设计成一起工作时,它能保证客户端始终只使用同一个产品族中的对象。
缺点:
当产品族中需要增加一个新的产品时,所有的工厂类都需要进行修改。
1.4.5 使用场景
-
当需要创建的对象是一系列相互关联或相互依赖的产品族时,如电器工厂中的电视机、洗衣机、空调等。
-
系统中有多个产品族,但每次只使用其中的某一族产品。如有人只喜欢穿某一个品牌的衣服和鞋。
-
系统中提供了产品的类库,且所有产品的接口相同,客户端不依赖产品实例的创建细节和内部结构。
如:输入法换皮肤,一整套一起换。生成不同操作系统的程序。
2 策略模式
2.1 概述
先看下面的图片,我们去旅游选择出行模式有很多种,可以骑自行车、可以坐汽车、可以坐火车、可以坐飞机。
作为一个程序猿,开发需要选择一款开发工具,当然可以进行代码开发的工具有很多,可以选择Idea进行开发,也可以使用eclipse进行开发,也可以使用其他的一些开发工具。
定义:
该模式定义了一系列算法,并将每个算法封装起来,使它们可以相互替换,且算法的变化不会影响使用算法的客户。策略模式属于对象行为模式,它通过对算法进行封装,把使用算法的责任和算法的实现分割开来,并委派给不同的对象对这些算法进行管理。
2.2 结构
策略模式的主要角色如下:
-
抽象策略(Strategy)类:这是一个抽象角色,通常由一个接口或抽象类实现。此角色给出所有的具体策略类所需的接口。
-
具体策略(Concrete Strategy)类:实现了抽象策略定义的接口,提供具体的算法实现或行为。
-
环境(Context)类:持有一个策略类的引用,最终给客户端调用。
2.3 案例实现
【例】促销活动
一家百货公司在定年度的促销活动。针对不同的节日(春节、中秋节、圣诞节)推出不同的促销活动,由促销员将促销活动展示给客户。类图如下:
聚合关系可以用带空心菱形的实线来表示
代码如下:
定义百货公司所有促销活动的共同接口
public interface Strategy {void show();
}
定义具体策略角色(Concrete Strategy):每个节日具体的促销活动
//为春节准备的促销活动A
public class StrategyA implements Strategy {
public void show() {System.out.println("买一送一");}
}
//为中秋准备的促销活动B
public class StrategyB implements Strategy {
public void show() {System.out.println("满200元减50元");}
}
//为圣诞准备的促销活动C
public class StrategyC implements Strategy {
public void show() {System.out.println("满1000元加一元换购任意200元以下商品");}
}
定义环境角色(Context):用于连接上下文,即把促销活动推销给客户,这里可以理解为销售员
public class SalesMan { //持有抽象策略角色的引用 private Strategy strategy; public SalesMan(Strategy strategy) { this.strategy = strategy; } //向客户展示促销活动 public void salesManShow(){ strategy.show(); }
}
2.4 综合案例
2.4.1 概述
下图是gitee的登录的入口,其中有多种方式可以进行登录
-
用户名密码登录
-
短信验证码登录
-
微信登录
-
QQ登录
-
....
2.4.2 目前已实现的代码
(1)登录接口
说明 | |
---|---|
请求方式 | POST |
路径 | /api/user/login |
参数 | LoginReq |
返回值 | LoginResp |
请求参数:LoginReq
@Data
public class LoginReq {
private String name;private String password;
private String phone;private String validateCode;//手机验证码
private String wxCode;//用于微信登录/*** account : 用户名密码登录* sms : 手机验证码登录* we_chat : 微信登录*/private String type;
}
响应参数:LoginResp
@Data
public class LoginResp{private Integer userId;private String userName;private String roleCode;private String token; //jwt令牌private boolean success;
}
控制层LoginController
@RestController
@RequestMapping("/api/user")
public class LoginController {
@Autowiredprivate UserService userService;
@PostMapping("/login")public LoginResp login(@RequestBody LoginReq loginReq){return userService.login(loginReq);}
}
业务层UserService
@Service
public class UserService {
public LoginResp login(LoginReq loginReq){
if(loginReq.getType().equals("account")){System.out.println("用户名密码登录");
//执行用户密码登录逻辑
return new LoginResp();
}else if(loginReq.getType().equals("sms")){System.out.println("手机号验证码登录");
//执行手机号验证码登录逻辑
return new LoginResp();}else if (loginReq.getType().equals("we_chat")){System.out.println("微信登录");
//执行用户微信登录逻辑
return new LoginResp();}LoginResp loginResp = new LoginResp();loginResp.setSuccess(false);System.out.println("登录失败");return loginResp;}
}
注意:我们重点讲的是设计模式,并不是登录的逻辑,所以以上代码并没有真正的实现登录功能
(2)问题分析
-
业务层代码大量使用到了if...else,在后期阅读代码的时候会非常不友好,大量使用if...else性能也不高
-
如果业务发生变更,比如现在新增了QQ登录方式,这个时候需要修改业务层代码,违反了开闭原则
解决:
使用工厂方法设计模式+策略模式解决
2.4.3 代码改造(工厂+策略)
(1)整体思路
改造之后,不在service中写业务逻辑,让service调用工厂,然后通过service传递不同的参数来获取不同的登录策略(登录方式)
(2)具体实现
抽象策略类:UserGranter
/*** 抽象策略类*/
public interface UserGranter{
/*** 获取数据* @param loginReq 传入的参数* @return map值*/LoginResp login(LoginReq loginReq);
}
具体的策略:AccountGranter、SmsGranter、WeChatGranter
/*** 策略:账号登录**/
@Component
public class AccountGranter implements UserGranter{
@Overridepublic LoginResp login(LoginReq loginReq) {
System.out.println("登录方式为账号登录" + loginReq);// TODO// 执行业务操作 return new LoginResp();}
}
/*** 策略:短信登录*/
@Component
public class SmsGranter implements UserGranter{
@Overridepublic LoginResp login(LoginReq loginReq) {
System.out.println("登录方式为短信登录" + loginReq);// TODO// 执行业务操作
return new LoginResp();}
}
/*** 策略:微信登录*/
@Component
public class WeChatGranter implements UserGranter{
@Overridepublic LoginResp login(LoginReq loginReq) {
System.out.println("登录方式为微信登录" + loginReq);// TODO// 执行业务操作return new LoginResp();}
}
工程类:UserLoginFactory
/*** 操作策略的上下文环境类 工具类* 将策略整合起来 方便管理*/
@Component
public class UserLoginFactory implements ApplicationContextAware {
private static Map<String, UserGranter> granterPool = new ConcurrentHashMap<>();
@Autowiredprivate LoginTypeConfig loginTypeConfig;
/*** 从配置文件中读取策略信息存储到map中* {* account:accountGranter,* sms:smsGranter,* we_chat:weChatGranter* }** @param applicationContext* @throws BeansException*/@Overridepublic void setApplicationContext(ApplicationContext applicationContext) throws BeansException {loginTypeConfig.getTypes().forEach((k, y) -> {granterPool.put(k, (UserGranter) applicationContext.getBean(y));});}
/*** 对外提供获取具体策略** @param grantType 用户的登录方式,需要跟配置文件中匹配* @return 具体策略*/public UserGranter getGranter(String grantType) {UserGranter tokenGranter = granterPool.get(grantType);return tokenGranter;}
}
在application.yml文件中新增自定义配置
login:types:account: accountGrantersms: smsGranterwe_chat: weChatGranter
新增读取数据配置类
Getter
@Setter
@Configuration
@ConfigurationProperties(prefix = "login")
public class LoginTypeConfig {
private Map<String,String> types;
}
改造service代码
@Service
public class UserService {
@Autowiredprivate UserLoginFactory factory;
public LoginResp login(LoginReq loginReq){
UserGranter granter = factory.getGranter(loginReq.getType());if(granter == null){LoginResp loginResp = new LoginResp();loginResp.setSuccess(false);return loginResp;}LoginResp loginResp = granter.login(loginReq);return loginResp;}
}
大家可以看到我们使用了设计模式之后,业务层的代码就清爽多了,如果后期有新的需求改动,比如加入了QQ登录,我们只需要添加对应的策略就可以,无需再改动业务层代码。
2.4.4 举一反三
其实像这样的需求,在日常开发中非常常见,场景有很多,以下的情景都可以使用工厂模式+策略模式解决比如:
-
订单的支付策略
-
支付宝支付
-
微信支付
-
银行卡支付
-
现金支付
-
-
解析不同类型excel
-
xls格式
-
xlsx格式
-
-
打折促销
-
满300元9折
-
满500元8折
-
满1000元7折
-
-
物流运费阶梯计算
-
5kg以下
-
5kg-10kg
-
10kg-20kg
-
20kg以上
-
一句话总结:只要代码中有冗长的 if-else 或 switch 分支判断都可以采用策略模式优化
3 责任链设计模式
3.1 概述
在现实生活中,常常会出现这样的事例:一个请求有多个对象可以处理,但每个对象的处理条件或权限不同。例如,公司员工请假,可批假的领导有部门负责人、副总经理、总经理等,但每个领导能批准的天数不同,员工必须根据自己要请假的天数去找不同的领导签名,也就是说员工必须记住每个领导的姓名、电话和地址等信息,这增加了难度。这样的例子还有很多,如找领导出差报销、生活中的“击鼓传花”游戏等。
定义:
又名职责链模式,为了避免请求发送者与多个请求处理者耦合在一起,将所有请求的处理者通过前一对象记住其下一个对象的引用而连成一条链;当有请求发生时,可将请求沿着这条链传递,直到有对象处理它为止。
比较常见的springmvc中的拦截器,web开发中的filter过滤器
3.2 结构
职责链模式主要包含以下角色:
-
抽象处理者(Handler)角色:定义一个处理请求的接口,包含抽象处理方法和一个后继连接。
-
具体处理者(Concrete Handler)角色:实现抽象处理者的处理方法,判断能否处理本次请求,如果可以处理请求则处理,否则将该请求转给它的后继者。
-
客户类(Client)角色:创建处理链,并向链头的具体处理者对象提交请求,它不关心处理细节和请求的传递过程。
3.2 案例实现
处理订单的操作
类图:
代码:
抽象处理者
package com.kjz.designpattern.chain;
/*** 抽象处理者*/
public abstract class Handler {
protected Handler handler;
public void setNext(Handler handler) {this.handler = handler;}
/*** 处理过程* 需要子类进行实现*/public abstract void process(OrderInfo order);
}
订单信息类:
package com.kjz.designpattern.chain;
import java.math.BigDecimal;
public class OrderInfo {
private String productId;private String userId;
private BigDecimal amount;
public String getProductId() {return productId;}
public void setProductId(String productId) {this.productId = productId;}
public String getUserId() {return userId;}
public void setUserId(String userId) {this.userId = userId;}
public BigDecimal getAmount() {return amount;}
public void setAmount(BigDecimal amount) {this.amount = amount;}
}
具体处理者:
/*** 订单校验*/
public class OrderValidition extends Handler {
@Overridepublic void process(OrderInfo order) {System.out.println("校验订单基本信息");//校验handler.process(order);}
}
/*** 补充订单信息*/
public class OrderFill extends Handler {@Overridepublic void process(OrderInfo order) {System.out.println("补充订单信息");handler.process(order);}
}
/*** 计算金额*/
public class OrderAmountCalcuate extends Handler {@Overridepublic void process(OrderInfo order) {System.out.println("计算金额-优惠券、VIP、活动打折");handler.process(order);}
}
/*** 订单入库*/
public class OrderCreate extends Handler {@Overridepublic void process(OrderInfo order) {System.out.println("订单入库");}
}
客户类:
public class Application {
public static void main(String[] args) {//检验订单Handler orderValidition = new OrderValidition();//补充订单信息Handler orderFill = new OrderFill();//订单算价Handler orderAmountCalcuate = new OrderAmountCalcuate();//订单落库Handler orderCreate = new OrderCreate();
//设置责任链路orderValidition.setNext(orderFill);orderFill.setNext(orderAmountCalcuate);orderAmountCalcuate.setNext(orderCreate);
//开始执行orderValidition.process(new OrderInfo());}
}
3.3 优缺点
优点
-
降低了对象之间的耦合度
该模式降低了请求发送者和接收者的耦合度。
-
增强了系统的可扩展性
可以根据需要增加新的请求处理类,满足开闭原则。
-
增强了给对象指派职责的灵活性
当工作流程发生变化,可以动态地改变链内的成员或者修改它们的次序,也可动态地新增或者删除责任。
-
责任链简化了对象之间的连接
一个对象只需保持一个指向其后继者的引用,不需保持其他所有处理者的引用,这避免了使用众多的 if 或者 if···else 语句。
-
责任分担
每个类只需要处理自己该处理的工作,不能处理的传递给下一个对象完成,明确各类的责任范围,符合类的单一职责原则。
缺点:
-
不能保证每个请求一定被处理。由于一个请求没有明确的接收者,所以不能保证它一定会被处理,该请求可能一直传到链的末端都得不到处理。
-
对比较长的职责链,请求的处理可能涉及多个处理对象,系统性能将受到一定影响。
-
职责链建立的合理性要靠客户端来保证,增加了客户端的复杂性,可能会由于职责链的错误设置而导致系统出错,如可能会造成循环调用。
3.4 举一反三
-
内容审核(视频、文章、课程….)
-
订单创建
-
简易流程审批
相关文章:
java面试设计模式篇
面试专题-设计模式 前言 在平时的开发中,涉及到设计模式的有两块内容,第一个是我们平时使用的框架(比如spring、mybatis等),第二个是我们自己开发业务使用的设计模式。 面试官一般比较关心的是你在开发过程中&#…...
桥接模式:解耦抽象与实现,实现灵活多变的扩展结构
文章目录 一、引言二、应用场景与技术背景三、模式定义与实现四、实例详解五、优缺点分析总结: 一、引言 桥接模式是一种结构型设计模式,它将抽象部分与它的实现部分分离,使它们可以独立变化。这种模式通过创建一个抽象层和实现层的结构&…...
HUAWEI Programming Contest 2024(AtCoder Beginner Contest 342)
D - Square Pair 题目大意 给一长为的数组,问有多少对,两者相乘为非负整数完全平方数 解题思路 一个数除以其能整除的最大的完全平方数,看前面有多少个与其余数相同的数,两者乘积满足条件(已经是完全平方数的部分无…...
Heap sorting
堆排序比较特殊,采用数组表示堆。 先将数组表示成大根堆或者小根堆。然后从堆中依次取根,最后形成有序序列。 #include<bits/stdc.h> using namespace std;const int N 1e5 10; int a[N];void bigheap(int* a, int start, int len) {if(start …...
开源模型应用落地-qwen2模型小试-入门篇(六)
一、前言 经过前五篇“qwen模型小试”文章的学习,我们已经熟练掌握qwen大模型的使用。然而,就在前几天开源社区又发布了qwen1.5版本,它是qwen2模型的测试版本。在基于transformers的使用方式上有较大的调整,现在,我们赶紧跟上脚步,去体验一下新版本模型的推理质量。 二、…...
c#程序,oracle使用Devart驱动解决第第三方库是us7ascii,数据乱码的问题
最近做项目,要跟对方系统的库进行读写,结果发现对方采用的是oracle的us7ascii编码,我们系统默认采用的是ZHS16GBK,导致我们客户端读取和写入对方库的数据都是乱码,搜索网上,发现需要采用独立的oracle驱动去…...
代码随想录算法训练营第四一天 | 背包问题
目录 背包问题01背包二维dp数组01背包一维 dp 数组(滚动数组)分割等和子集 LeetCode 背包问题 01背包 有n件物品和一个最多能背重量为 w 的背包,第i件物品的重量是weight[i],得到的价值是value[i] 。每件物品只能用一次&#x…...
AIDL的工作原理与使用示例 跨进程通信 远程方法调用RPC
AIDL的介绍与使用 AIDL(Android Interface Definition Language)是Android中用于定义客户端和服务端之间通信接口的一种接口定义语言。它允许你定义客户端和服务的通信协议,用于在不同的进程间或同一进程的不同组件间进行数据传递。AIDL通过…...
K8S部署Java项目 pod报错 logs日志内容:no main manifest attribute, in app.jar
天行健,君子以自强不息;地势坤,君子以厚德载物。 每个人都有惰性,但不断学习是好好生活的根本,共勉! 文章均为学习整理笔记,分享记录为主,如有错误请指正,共同学习进步。…...
SQL实现模糊查询的四种方法总结
目录 一、一般模糊查询 二、利用通配符查询 1. _ 表示任意的单个字符 2. % 表示匹配任意多个任意字符 3. [ ]表示筛选范围 4. 查询包含通配符的字符串 一、一般模糊查询 1. 单条件查询 //查询所有姓名包含“张”的记录select * from student where name like 张 2. 多条…...
爬虫基本库的使用(urllib库的详细解析)
学习爬虫,其基本的操作便是模拟浏览器向服务器发出请求,那么我们需要从哪个地方做起呢?请求需要我们自己构造吗? 我们需要关心请求这个数据结构怎么实现吗? 需要了解 HTTP、TCP、IP层的网络传输通信吗? 需要知道服务器如何响应以及响应的原理吗? 可…...
【PyQt5桌面应用开发】3.Qt Designer快速入门(控件详解)
一、Qt Designer简介 Qt Designer是PyQt程序UI界面的实现工具,可以帮助我们快速开发 PyQt 程序的速度。它生成的 UI 界面是一个后缀为 .ui 的文件,可以通过 pyiuc 转换为 .py 文件。 Qt Designer工具使用简单,可以通过拖拽和点击完成复杂界面…...
react useMemo 用法
1,useCallback 的功能完全可以由 useMemo 所取代,如果你想通过使用 useMemo 返回一个记忆函数也是完全可以的。 usecallback(fn,inputs)is equivalent to useMemo(()> fn, inputs). 区别是:useCallback不会执行第一个参数函数,而是将它返…...
python学习笔记 - 标准库函数
概述 为了方便程序员快速编写Python脚本程序,Python提供了很多好用的功能模块,它们内置于Python系统,也称为内置函数(Built-in Functions,BlF),Python 内置函数是 Python 解释器提供的一组函数,无需额外导…...
校招失败后,在小公司熬了 2 年终于进了字节跳动,竭尽全力....
其实两年前校招的时候就往字节投了一次简历,结果很明显凉了,随后这个理想就被暂时放下了,但是这个种子一直埋在心里这两年除了工作以外,也会坚持写博客,也因此结识了很多优秀的小伙伴,从他们身上学到了特别…...
PYTHON-使用正则表达式进行模式匹配
目录 Python 正则表达式Finding Patterns of Text Without Regular ExpressionsFinding Patterns of Text with Regular ExpressionsCreating Regex ObjectsMatching Regex ObjectsReview of Regular Expression MatchingMore Pattern Matching with Regular ExpressionsGroupi…...
Fiddler工具 — 19.Fiddler抓包HTTPS请求(二)
5、查看证书是否安装成功 方式一: 点击Tools菜单 —> Options... —> HTTPS —> Actions 选择第三项:Open Windows Certificate Manager打开Windows证书管理器。 打开Windows证书管理器,选择操作—>查看证书,在搜索…...
架构设计:流式处理与实时计算
引言 随着大数据技术的不断发展,流式处理和实时计算在各行各业中变得越来越重要。那么什么是流式处理呢?我们又该怎么使用它?流式处理允许我们对数据流进行实时分析和处理,而实时计算则使我们能够以低延迟和高吞吐量处理数据。本…...
Linux系统安装zookeeper
Linux安装zookeeper 安装zookeeper之前需要安装jdk,确认jdk环境没问题之后再开始安装zookeeper 下载zookeeper压缩包,官方下载地址:Apache Download Mirrors 将zookeeper压缩包拷贝到Linux并解压 # (-C 路径)可以解压到指定路径 tar -zxv…...
【前端素材】推荐优质后台管理系统Modernize平台模板(附源码)
一、需求分析 后台管理系统是一种用于管理和控制网站、应用程序或系统后台操作的软件工具,通常由授权用户(如管理员、编辑人员等)使用。它提供了一种用户友好的方式来管理网站或应用程序的内容、用户、数据等方面的操作,并且通常…...
二、Vue组件化编程
2、Vue组件化编程 2.1 非单文件组件 <div id"root"><school></school><hr><student></student> </div> <script type"text/javascript">//创建 school 组件const school Vue.extend({template: <div&…...
JVM跨代引用垃圾回收
1. 跨代引用概述 在Java堆内存中,年轻代和老年代之间存在的对象相互引用,假设现在要进行一次新生代的YGC,但新生代中的对象可能被老年代所引用的,为了找到新生代中的存活对象,不得不遍历整个老年代。这样明显效率很低…...
AI:135-基于卷积神经网络的艺术品瑕疵检测与修复
🚀点击这里跳转到本专栏,可查阅专栏顶置最新的指南宝典~ 🎉🎊🎉 你的技术旅程将在这里启航! 从基础到实践,深入学习。无论你是初学者还是经验丰富的老手,对于本专栏案例和项目实践都有参考学习意义。 ✨✨✨ 每一个案例都附带关键代码,详细讲解供大家学习,希望…...
C++标准头文件汇总及功能说明
文章目录 algorithmbitsetcctypecerrnoclocalecmathcstdioctimedequeiostreamexceptionfstreamfunctionallimitslistmapiosiosfwdsetsstreamstackstdexceptstreambufcstringutilityvectorcwcharcwctype algorithm algorithm头文件是C的标准算法库,它主要用在容器上。…...
glTF 添加数据属性(extras)
使用3D 模型作为可视化界面的一个关键是要能够在3D模型中添加额外的数据属性,利用这些数据属性能够与后台的信息模型建立对应关系,例如后台信息模型是opcua 信息模型的话,在3D模型中要能够包含OPC UA 的NodeId,BrowserName 等基本…...
linux系统消息中间件rabbitmq普通集群的部署
rabbitmq普通集群的部署 普通集群准备环境查询版本对应安装rabbitmq软件启动创建登录用户开启用户远程登录查看端口 部署集群创建数据存放目录和日志存放目录:拷⻉erlang.cookie将其他两台服务器作为节点加⼊节点集群中查看集群状态创建新的队列 普通集群准备环境 配置hosts⽂件…...
TextCNN:文本分类卷积神经网络
模型原理 1、前言2、模型结构3、示例3.1、词向量层3.2、卷积层3.3、最大池化层3.4、Fully Connected层 4、总结 1、前言 TextCNN 来源于《Convolutional Neural Networks for Sentence Classification》发表于2014年,是一个经典的模型,Yoon Kim将卷积神…...
欧几里得和《几何原本》
欧几里得和《几何原本》 欧几里得(Euclid),公元前约300年生于古希腊,被认为是几何学的奠基人之一。他的主要成就是编写了一本名为《几何原本》(Elements)的著作,这本书成为了几何学的经典教材&a…...
linux c++ 开发 tensorrt 安装
tensorrt 官方下载地址(需要注册账号登录):Log in | NVIDIA Developer 根据系统发行版和CUDA版本 (nvcc -V) 选择合适的安装包 EA(early access)版本代表抢先体验。 GA(general availability)代…...
Redis高并发分布锁实战
Redis高并发分布锁实战 问题场景 场景一: 没有捕获异常 // 仅仅加锁 // 读取 stock15 Boolean ret stringRedisTemplate.opsForValue().setIfAbsent("lock_key", "1"); // jedis.setnx(k,v) // TODO 业务代码 stock-- stringRedisTemplate.delete(&quo…...
迷你主机做网站/网站seo优化检测
好几种IE6的BUG只要添加ZOOM:1,问题就迎刃而解,主要原因是触发了layout。layout这个定义属于IE,当元素触发了layout或者默认具有layout,则这个元素自己会对自身的内容进行计算大小和组织。否则,这个元素将依赖于父元素…...
网站建设技术和销售工资/指数基金有哪些
新的项目开始了,这一次是做一个网站类似于QQ空间那样的,基本功能比如说写日志,说说之类的都要有(说说是要有楼中楼嵌套的,应该能够上传图片),还要可以修改个人信息。登录注册之类的更不用说了&a…...
微信端的网站开发python/免费网站模板库
(农村老宅)(点击即可收听)桃花盛开正清明,门前小路依旧在,唯有不见已故人转瞬间,又是一年一度清明节年少,听雨歌楼上,红烛昏罗帐,不懂清明时节的庄严与肃穆,清朗,明净如今,人到中年,听雨客舟中,江阔云低,断雁叫西风世事无常,历经春夏秋冬,生老病死,在悲欢…...
排名好的锦州网站建设/长尾关键词查询工具
织梦DEDECMS网站后台登录为一片空白怎么解决 最近有站长朋友反馈他们后台出现空白情况,开启织梦里面错误调试,发现后台显示错误如下图 (此图片来源于网络,如有侵权,请联系删除! ) 原来这里是因为php里面关闭了PHP输出缓存导致的…...
做pc端网站市场/河南郑州网站推广优化外包
由光子工作室群自研出品,NoSQL分布式数据库TcaplusDB提供数据服务的超真实开放世界生存手游《黎明觉醒》即将在6月25日迎来“长夜已尽,黎明将至”终极测试! 基于虚幻引擎4打造,《黎明觉醒》为玩家展现了一个以开放世界探索、真实…...
wordpress图形验证码/公司seo是什么意思
问题描述按照网友提供的 phoenix 映射已存在的 hbase 表 demo 时,表映射正常,但是使用 phoenix 查询时,一直查询不到数据。举个栗子:hbase shell 插入数据create test1,iput test1,1,i:name,zhangsanput test1,2,i:name,lisiput t…...