设计模式之为什么要学好设计模式
目录
- 1 回顾软件设计原则
- 2 设计模式总览
- 3 经典框架都在用设计模式解决问题
1 回顾软件设计原则
不用设计模式并非不可以,但是用好设计模式能帮助我们更好地解决实际问题,设计模式最重要的是解耦。设计模式天天都在用,但自己却无感知。我们把设计模式作为一个专题,主要是学习设计模式是如何总结经验的,把经验为自己所用。学设计模式也是锻炼将业务需求转换技术实现的一种非常有效的方式。
设计原则 | 解释 |
---|---|
开闭原则 | 对扩展开放,对修改关闭 |
依赖倒置原则 | 通过抽象使各个类或者模块不相互影响,实现松耦合。 |
单一职责原则 | 一个类、接口、方法只做一件事。 |
接口隔离原则 | 尽量保证接口的纯洁性,客户端不应该依赖不需要的接口。 |
迪米特法则 | 又叫最少知道原则,一个类对其所依赖的类知道得越少越好。 |
里氏替换原则 | 子类可以扩展父类的功能但不能改变父类原有的功能。 |
合成复用原则 | 尽量使用对象组合、聚合,而不使用继承关系达到代码复用的目的。 |
2 设计模式总览
写出优雅的代码以下是超级乱的代码
public void setExammingForm(ExammingForm curForm,String parameters)throws BaseException { ...JSONObject jsonObj = new JSONObject(parameters);//试卷主键 if(jsonObj.getString("examinationPaper_id")!= null && (!jsonObj.getString ("examinationPaper_id").equals("")))curForm.setExaminationPaper_id(jsonObj.getLong("examinationPaper_id"));//剩余时间 if(jsonObj.getString("leavTime") != null && (!jsonObj.getString("leavTime").equals("")))curForm.setLeavTime(jsonObj.getInt("leavTime"));//单位主键 if(jsonObj.getString("organization_id")!= null && (!jsonObj.getString ("organization_id").equals("")))curForm.setOrganization_id(jsonObj.getLong("organization_id"));//考试主键 if(jsonObj.getString("id")!= null && (!jsonObj.getString("id").equals("")))curForm.setId(jsonObj.getLong("id"));//考场主键 if(jsonObj.getString("examroom_id")!= null && (!jsonObj.getString ("examroom_id").equals("")))curForm.setExamroom_id(jsonObj.getLong("examroom_id"));//用户主键 if(jsonObj.getString("user_id")!= null && (!jsonObj.getString("user_id").equals("")))curForm.setUser_id(jsonObj.getLong("user_id"));//专业代码 if(jsonObj.getString("specialtyCode")!= null && (!jsonObj.getString ("specialtyCode").equals("")))curForm.setSpecialtyCode(jsonObj.getLong("specialtyCode"));//报考岗位 if(jsonObj.getString("postionCode")!= null && (!jsonObj.getString ("postionCode").equals("")))curForm.setPostionCode(jsonObj.getLong("postionCode"));//报考等级 if(jsonObj.getString("gradeCode")!= null && (!jsonObj.getString ("gradeCode").equals("")))curForm.setGradeCode(jsonObj.getLong("gradeCode"));//考试开始时间 curForm.setExamStartTime(jsonObj.getString("examStartTime"));//考试结束时间 curForm.setExamEndTime(jsonObj.getString("examEndTime")); ...}
优雅的赋值:
注:这里的下划线可以转换一下驼峰这里我要总结几篇文章
@JSONType(naming= PropertyNamingStrategy.SnakeCase)
public class ExammingFormVo extends ExammingForm{private String examinationPaperId; //试卷主键 private String leavTime; //剩余时间 private String organizationId; //单位主键 private String id; //考试主键 private String examRoomId; //考场主键 private String userId; //用户主键 private String specialtyCode; //专业代码 private String postionCode; //报考岗位 private String gradeCode; //报考等级 private String examStartTime; //考试开始时间 private String examEndTime; //考试结束时间 ...}public void setExammingForm(ExammingForm form,String parameters)throws BaseException {try {JSONObject json = new JSONObject(parameters);ExammingFormVo vo = JSONObject.parseObject(json,ExammingFormVo.class);form = vo;}catch (Exception e){e.printStackTrace();}}
更好地重构项目
请查看以下代码发现问题
public void save(Student stu){String sql = "INSERT INTO t_student(name,age) VALUES(?,?)";Connection conn = null;Statement st = null;try{//1. 加载注册驱动 Class.forName("com.mysql.jdbc.Driver");//2. 获取数据库连接 conn=DriverManager.getConnection("jdbc:mysql:///jdbc_demo","root","root");//3. 创建语句对象 PreparedStatement ps=conn.prepareStatement(sql);ps.setObject(1,stu.getName());ps.setObject(2,stu.getAge());//4. 执行SQL语句 ps.executeUpdate();//5. 释放资源 }catch(Exception e){e.printStackTrace();}finally{try{if(st != null)st.close();}catch(SQLException e){e.printStackTrace();}finally{try{if(conn != null)conn.close();}catch(SQLException e){e.printStackTrace();}}}}//删除学生信息 public void delete(Long id){String sql = "DELETE FROM t_student WHERE id=?";Connection conn = null;Statement st = null;try{//1. 加载注册驱动 Class.forName("com.mysql.jdbc.Driver");//2. 获取数据库连接 conn=DriverManager.getConnection("jdbc:mysql:///jdbc_demo","root","root");//3. 创建语句对象 PreparedStatement ps = conn.prepareStatement(sql);ps.setObject(1,id);//4. 执行SQL语句 ps.executeUpdate();//5. 释放资源 }catch(Exception e){e.printStackTrace();}finally{try{if(st != null)st.close();}catch(SQLException e){e.printStackTrace();}finally{try{if(conn != null)conn.close();}catch(SQLException e){e.printStackTrace();}}}}//修改学生信息 public void update(Student stu){String sql = "UPDATE t_student SET name=?,age=? WHERE id=?";Connection conn = null;Statement st = null;try{//1. 加载注册驱动 Class.forName("com.mysql.jdbc.Driver");//2. 获取数据库连接 conn=DriverManager.getConnection("jdbc:mysql:///jdbc_demo","root","root");//3. 创建语句对象 PreparedStatement ps = conn.prepareStatement(sql);ps.setObject(1,stu.getName());ps.setObject(2,stu.getAge());ps.setObject(3,stu.getId());//4. 执行SQL语句 ps.executeUpdate();//5. 释放资源 }catch(Exception e){e.printStackTrace();}finally{try{if(st != null)st.close();}catch(SQLException e){e.printStackTrace();}finally{try{if(conn != null)conn.close();}catch(SQLException e){e.printStackTrace();}}}}
上述代码的功能没问题,但是代码重复得太多,因此可以进行抽取,把重复代码放到一个工具类JdbcUtil里。
工具类:
public class JdbcUtil {private JdbcUtil() { }static {//1. 加载注册驱动 try {Class.forName("com.mysql.jdbc.Driver");} catch (Exception e) {e.printStackTrace();}}public static Connection getConnection() {try {//2. 获取数据库连接 return DriverManager.getConnection("jdbc:mysql:///jdbc_demo", "root", "root");} catch (Exception e) {e.printStackTrace();}return null;}//释放资源 public static void close(ResultSet rs, Statement st, Connection conn) {try {if (rs != null)rs.close();} catch (SQLException e) {e.printStackTrace();} finally {try {if (st != null)st.close();} catch (SQLException e) {e.printStackTrace();} finally {try {if (conn != null)conn.close();} catch (SQLException e) {e.printStackTrace();}}}}}
只需要在实现类中直接调用工具类JdbcUtil中的方法即可。
//增加学生信息public void save(Student stu) {String sql = "INSERT INTO t_student(name,age) VALUES(?,?)";Connection conn = null;PreparedStatement ps=null;try {conn = JDBCUtil.getConnection();//3. 创建语句对象ps = conn.prepareStatement(sql);ps.setObject(1, stu.getName());ps.setObject(2, stu.getAge());//4. 执行SQL语句ps.executeUpdate();//5. 释放资源} catch (Exception e) {e.printStackTrace();} finally {JDBCUtil.close(null, ps, conn);}}//删除学生信息public void delete(Long id) {String sql = "DELETE FROM t_student WHERE id=?";Connection conn = null;PreparedStatement ps = null;try {conn=JDBCUtil.getConnection();//3. 创建语句对象ps = conn.prepareStatement(sql);ps.setObject(1, id);//4. 执行SQL语句ps.executeUpdate();//5. 释放资源} catch (Exception e) {e.printStackTrace();} finally {JDBCUtil.close(null, ps, conn);}}//修改学生信息public void update(Student stu) {String sql = "UPDATE t_student SET name=?,age=? WHERE id=?";Connection conn = null;PreparedStatement ps = null;try {conn=JDBCUtil.getConnection();//3. 创建语句对象ps = conn.prepareStatement(sql);ps.setObject(1, stu.getName());ps.setObject(2, stu.getAge());ps.setObject(3, stu.getId());//4. 执行SQL语句ps.executeUpdate();//5. 释放资源} catch (Exception e) {e.printStackTrace();} finally {JDBCUtil.close(null, ps, conn);}}public Student get(Long id) {String sql = "SELECT * FROM t_student WHERE id=?";Connection conn = null;Statement st = null;ResultSet rs = null;PreparedStatement ps=null;try {conn = JDBCUtil.getConnection();//3. 创建语句对象ps = conn.prepareStatement(sql);ps.setObject(1, id);//4. 执行SQL语句rs = ps.executeQuery();if (rs.next()) {String name = rs.getString("name");int age = rs.getInt("age");Student stu = new Student(id, name, age);return stu;}//5. 释放资源} catch (Exception e) {e.printStackTrace();} finally {JDBCUtil.close(rs, ps, conn);}return null;}public List<Student> list() {List<Student> list = new ArrayList<>();String sql = "SELECT * FROM t_student ";Connection conn = null;Statement st = null;ResultSet rs = null;PreparedStatement ps=null;try {conn=JDBCUtil.getConnection();//3. 创建语句对象ps = conn.prepareStatement(sql);//4. 执行SQL语句rs = ps.executeQuery();while (rs.next()) {long id = rs.getLong("id");String name = rs.getString("name");int age = rs.getInt("age");Student stu = new Student(id, name, age);list.add(stu);}//5. 释放资源} catch (Exception e) {e.printStackTrace();} finally {JDBCUtil.close(rs, ps, conn);}return list;}
虽然完成了重复代码的抽取,但数据库中的账号密码等直接显示在代码中,不利于后期账户密码改动的维护。可以建立一个db.propertise文件,用来存储这些信息。
driverClassName=com.mysql.jdbc.Driver url=jdbc:mysql:///jdbcdemo username=root password=root
只需要在工具类JdbcUtil中获取里面的信息即可。
static {//1. 加载注册驱动 try {ClassLoader loader = Thread.currentThread().getContextClassLoader();InputStream inputStream = loader.getResourceAsStream("db.properties");p = new Properties();p.load(inputStream);Class.forName(p.getProperty("driverClassName"));} catch (Exception e) {e.printStackTrace();}}public static Connection getConnection() {try {//2. 获取数据库连接 return DriverManager.getConnection(p.getProperty("url"), p.getProperty("username"),p.getProperty("password"));} catch (Exception e) {e.printStackTrace();}return null;}
代码抽取到这里,貌似已经完成,但在实现类中,依然存在部分重复代码,在DML操作中,除了SQL和设置值的不同,其他都相同,把相同的部分抽取出来,把不同的部分通过参数传递进来,无法直接放在工具类中。此时,可以创建一个模板类JdbcTemplate,创建一个DML和DQL的模板来对代码进行重构。
//查询统一模板public static List<Student> query(String sql,Object...params){List<Student> list=new ArrayList<>();Connection conn = null;PreparedStatement ps=null;ResultSet rs = null;try {conn=JDBCUtil.getConnection();ps=conn.prepareStatement(sql);//设置值for (int i = 0; i < params.length; i++) {ps.setObject(i+1, params[i]);}rs = ps.executeQuery();while (rs.next()) {long id = rs.getLong("id");String name = rs.getString("name");int age = rs.getInt("age");Student stu = new Student(id, name, age);list.add(stu);}//5. 释放资源} catch (Exception e) {e.printStackTrace();} finally {JDBCUtil.close(rs, ps, conn);}return list;}实现类直接调用方法即可。//增加学生信息public void save(Student stu) {String sql = "INSERT INTO t_student(name,age) VALUES(?,?)";Object[] params=new Object[]{stu.getName(),stu.getAge()};JdbcTemplate.update(sql, params);}//删除学生信息public void delete(Long id) {String sql = "DELETE FROM t_student WHERE id = ?";JdbcTemplate.update(sql, id);}//修改学生信息public void update(Student stu) {String sql = "UPDATE t_student SET name = ?,age = ? WHERE id = ?";Object[] params=new Object[]{stu.getName(),stu.getAge(),stu.getId()};JdbcTemplate.update(sql, params);}public Student get(Long id) {String sql = "SELECT * FROM t_student WHERE id=?";List<Student> list = JDBCTemplate.query(sql, id);return list.size()>0? list.get(0):null;}public List<Student> list() {String sql = "SELECT * FROM t_student ";return JDBCTemplate.query(sql);}
这样重复的代码基本就解决了,但有一个很严重的问题,就是这个程序DQL操作中只能处理Student类和t_student表的相关数据,无法处理其他类,比如Teacher类和t_teacher表。不同的表(不同的对象)应该有不同的列,不同列处理结果集的代码就应该不一样,处理结果集的操作只有DAO自己最清楚。也就是说,处理结果的方法根本就不应该放在模板方法中,应该由每个DAO自己来处理。因此,可以创建一个IRowMapper接口来处理结果集。
public interface IRowMapper {//处理结果集 List rowMapper(ResultSet rs) throws Exception;}
DQL模板类中调用IRowMapper接口中的handle方法,提醒实现类自己去实现mapping方法。
public static List<Student> query(String sql,IRowMapper rsh, Object...params){List<Student> list = new ArrayList<>();Connection conn = null;PreparedStatement ps=null;ResultSet rs = null;try {conn = JdbcUtil.getConnection();ps = conn.prepareStatement(sql);//设置值 for (int i = 0; i < params.length; i++) {ps.setObject(i+1, params[i]);}rs = ps.executeQuery();return rsh.mapping(rs);//5. 释放资源 } catch (Exception e) {e.printStackTrace();} finally {JdbcUtil.close(rs, ps, conn);}return list ;}
实现类自己去实现IRowMapper接口的mapping方法,想要处理什么类型的数据在里面定义即可。
public Student get(Long id) {String sql = "SELECT * FROM t_student WHERE id = ?";List<Student> list = JdbcTemplate.query(sql,new StudentRowMapper(), id);return list.size()>0? list.get(0):null;}public List<Student> list() {String sql = "SELECT * FROM t_student ";return JdbcTemplate.query(sql,new StudentRowMapper());}class StudentRowMapper implements IRowMapper{public List mapping(ResultSet rs) throws Exception {List<Student> list=new ArrayList<>();while(rs.next()){long id = rs.getLong("id");String name = rs.getString("name");int age = rs.getInt("age");Student stu=new Student(id, name, age);list.add(stu);}return list;}}
到这里为止,实现ORM的关键代码已经大功告成,但是DQL查询不单单要查询学生信息(List类型),还要查询学生数量,这时就要通过泛型来完成。
public interface IRowMapper<T> {//处理结果集 T mapping(ResultSet rs) throws Exception;}public static <T> T query(String sql,IRowMapper<T> rsh, Object...params){Connection conn = null;PreparedStatement ps=null;ResultSet rs = null;try {conn = JdbcUtil.getConnection();ps = conn.prepareStatement(sql);//设置值 for (int i = 0; i < params.length; i++) {ps.setObject(i+1, params[i]);}rs = ps.executeQuery();return rsh.mapping(rs);//5. 释放资源 } catch (Exception e) {e.printStackTrace();} finally {JdbcUtil.close(rs, ps, conn);}return null;}
StudentRowMapper类的代码如下。
class StudentRowMapper implements IRowMapper<List<Student>>{public List<Student> mapping(ResultSet rs) throws Exception {List<Student> list=new ArrayList<>();while(rs.next()){long id = rs.getLong("id");String name = rs.getString("name");int age = rs.getInt("age");Student stu=new Student(id, name, age);list.add(stu);}return list;}}
这样,不仅可以查询List,还可以查询学生数量。
public Long getCount(){String sql = "SELECT COUNT(*) total FROM t_student";Long totalCount = (Long) JdbcTemplate.query(sql,new IRowMapper<Long>() {public Long mapping(ResultSet rs) throws Exception {Long totalCount = null;if(rs.next()){totalCount = rs.getLong("total");}return totalCount;}});return totalCount;}
这样,重构设计就已经完成,好的代码能让我们以后维护更方便,因此学会对代码的重构是非常重要的。
3 经典框架都在用设计模式解决问题
比如,Spring就是一个把设计模式用得淋漓尽致的经典框架。本书会结合JDK、Spring、MyBatis、Netty、Tomcat、Dubbo等经典框架的源码对设计模式展开分析,帮助大家更好、更深入地理解设计模式在框架源码中的落地。
经典框架都在用设计模式解决问题
Spring就是一个把设计模式用得淋漓尽致的经典框架,其实从类的命名就能看出来,我来一一列举:
设计模式名称 | 举例 |
---|---|
工厂模式 | BeanFactory |
装饰器模式 | BeanWrapper |
代理模式 | AopProxy |
委派模式 | DispatcherServlet |
策略模式 | HandlerMapping |
适配器模式 | HandlerAdapter |
模板模式 | JdbcTemplate |
观察者模式 | ContextLoaderListener |
围绕 Spring 的 IOC、AOP、MVC、JDBC这样的思路展开,根据其设计类型来设计讲解顺序:
类型 | 名称 | 英文 |
---|---|---|
创建型模式 | 工厂模式 | Factory Pattern |
单例模式 | Singleton Pattern | |
原型模式 | Prototype Pattern | |
结构型模式 | 适配器模式 | Adapter Pattern |
装饰器模式 | Decorator Patter | |
代理模式 | Proxy Pattern | |
行为性模式 | 策略模式 | Strategy Pattern |
模板模式 | Template Pattern | |
委派模式 | Delegate Pattern | |
观察者模式 | Observer Pattern |
相关文章:
设计模式之为什么要学好设计模式
目录1 回顾软件设计原则2 设计模式总览3 经典框架都在用设计模式解决问题1 回顾软件设计原则 不用设计模式并非不可以,但是用好设计模式能帮助我们更好地解决实际问题,设计模式最重要的是解耦。设计模式天天都在用,但自己却无感知。我们把设…...
大数据时代的小数据神器 - asqlcell
自从Google发布了经典的MapReduce论文,以及Yahoo开源了Hadoop的实现,大数据这个词就成为了一个行业的热门。在不断提高的机器性能和各种层出不穷的工具框架加持下,数据分析开始从过去的采样抽查变成全量整体,原先被抽样丢弃的隐藏…...
【呕心沥血】整理全栈自动化测试技术(三):如何编写技术方案
前面两篇笔记我介绍了自动化测试前期调研注意事项和前置准备阶段切入点,有同学在后台提问: “做完前期的调研和准备工作,领导要求写一个落地方案并评审,自动化测试的落地方案该怎么写”? 首先这个要求我觉得挺正常&a…...
67. 二进制求和
文章目录题目描述竖式模拟转换为十进制计算题目描述 给你两个二进制字符串 a 和 b ,以二进制字符串的形式返回它们的和。 示例 1: 输入:a “11”, b “1” 输出:“100” 示例 2: 输入:a “1010”, b “1011” …...
1555数列极差(队列 优先队列 )
目录 题目描述 解题思路 代码部分 题目描述 在黑板上写了N个正整数作成的一个数列,进行如下操作:每一次擦去其中的两个数a和b,然后在数列中加入一个数a*b1,如此下去直至黑板上剩下一个数,在所有按这种操作方式最后得…...
代码随想录算法训练营第二十七天 | 93.复原IP地址,78.子集,90.子集II
一、参考资料复原IP地址题目链接/文章讲解:https://programmercarl.com/0093.%E5%A4%8D%E5%8E%9FIP%E5%9C%B0%E5%9D%80.html 视频讲解:https://www.bilibili.com/video/BV1XP4y1U73i/子集题目链接/文章讲解:https://programmercarl.com/0078.…...
jvm类加载器
概念 Bootstarp ClassLoader (引导类加载器) 加载String等核心的类Ext ClassLoader (拓展类加载器)System ClassLoader (系统类加载器) 加载用户自定义的类 关系 BootstrapClassLoader 包含 ExtClassLoaderExtClassLoader 包含 SystemClassLoader彼此是包含关系,不…...
Rust学习入门--【7】Rust 数据类型
类型系统 对于任何一门语言都是重中之重,因为它体现了语言所支持的不同类型的值。 类型系统 也是 IT 初学者最难啃的三座大山之一,而类型系统之所以难以理解,主要是没有合适的现成的参考体系。 我们说类型系统 存在的目的,就是 …...
阅读MySQL必知必会,查缺补漏
MySQL自带数据库 information_schema:是MySQL自带的数据库,主要保持MySQL数据库服务器的系统信息,比如数据库的名称,数据库表的名称,字段名称,存储权限等。 performance_schema:是MySQL系统自…...
MySQL数据库10——多表连接查询
数据如果在多个表里面,需要进行连接查询。 一般在pandas里面merge合并会用到一个索引,按这个索引的规则进行合并叫做有规则的等值连接。若不按规则连接,遍历两两组合的所有可能性,叫做笛卡尔积。 笛卡尔积连接 通常人们都会设置…...
华为OD机试 - 括号检查(Python)| 真题含思路
括号检查 题目 现有一字符串 仅由 (,),{,},[,] 六种括号组成,若字符串满足以下条件之一,则为无效字符串 任意类型的左右括号数量不相等 存在未按正确顺序(先左后右)闭合的括号, 输出括号的最大嵌套深度 若字符串无效则输出 0 0 <= 字符串长度 <= 100000 输入 一个只…...
安全渗透测试中的一款免费开源的超级关键词URL采集工具
安全渗透测试中的一款免费开源的超级关键词URL采集工具。 #################### 免责声明:工具本身并无好坏,希望大家以遵守《网络安全法》相关法律为前提来使用该工具,支持研究学习,切勿用于非法犯罪活动,对于恶意使…...
数据资产管理实践白皮书(6.0版)解读
目录 第一章数据资产管理概述 ( 一 ) 数据资产管理和数据要素的关系...
c/c++开发,无可避免的函数指针使用案例
一、函数指针简介 函数指针是指指向函数而非指向对象的指针。像其他指针一样,函数指针也指向某个特定的类型。函数类型由其返回类型以及形参表确定,而与函数名无关。例如: char* (*pf1)(char * p1,char *p2); 这是一个函数指针,其…...
QT(12)-QThreadPool
1 简介 QThreadPool是Qt框架中的一个类,提供了一组工作线程池。该线程池自动管理一组工作线程,在线程可用时分配任务。使用线程池的主要优点是,它可以减少创建和销毁线程的开销,因为可以重复使用线程。 线程池设计用于场景中&am…...
【Java|golang】1138. 字母板上的路径
我们从一块字母板上的位置 (0, 0) 出发,该坐标对应的字符为 board[0][0]。 在本题里,字母板为board [“abcde”, “fghij”, “klmno”, “pqrst”, “uvwxy”, “z”],如下所示。 我们可以按下面的指令规则行动: 如果方格存…...
Flink 1.14从简单到源码第三讲
文章目录 1.flink多流操作Api1.1split 分流操作1.2.侧输出流1.3.connect 连接操作1.4.union 操作1.5 coGroup 协同分组1.6 join1.7 broadcast 广播2.process3.并行度和Api3.1 任务提交简单流程3.2 task与算子链4. Flink 时间相关(窗口计算)4.1时间语义(窗口计算)4.2 新版api指定…...
淘宝API接口系列,获取购买到的商品订单列表,卖出的商品订单列表,订单详情,订单物流,买家信息,收货地址列表,买家token
custom自定义API操作buyer_order_list获取购买到的商品订单列表buyer_order_detail获取购买到的商品订单详情buyer_order_express获取购买到的商品订单物流buyer_address_list收货地址列表buyer_address_add添加收货地址buyer_info买家信息buyer_token买家tokenseller_order_li…...
ucos-ii 的任务调度原理和实现
ucosii 任务调度和原理1、ucos-ii 任务创建与任务调度 1.1、任务的创建 当你调用 OSTaskCreate( ) 进行任务的创建的时候,会初始化任务的堆栈、保存cpu的寄存器、创建任务的控制块(OS_TCB)等的操作; if (OSTCBPrioTbl[prio] (OS_…...
Solon2 开发之容器,七、切面与函数环绕拦截
想要环绕拦截一个 Bean 的函数。需要三个前置条件: 通过注解做为“切点”,进行拦截(不能无缘无故给拦了吧?费性能)Bean 的 method 是被代理的在 Bean 被扫描之前,完成环绕拦截的注册 1、定义切点和注册环…...
代码随想录第十天(28)
文章目录28. 找出字符串中第一个匹配项的下标看答案KMPnext数组(前缀表)最长公共前后缀如何计算前缀表前缀表与next数组时间复杂度分析28. 找出字符串中第一个匹配项的下标 莫得思路……好久没做题,都已经忘得差不多了 看答案 其实就是自己…...
循环队列来了解一下!!
笔者在之前的一篇文章,详细的介绍了:队列之单向链表与双向链表的模拟实现:https://blog.csdn.net/weixin_64308540/article/details/128742090?spm1001.2014.3001.5502 感兴趣的各位老铁,可以参考一下啦!下面进入循环…...
Idea打包springboot项目war包,测试通过
pom.xml文件 <!--包名以及版本号,这个是打包时候使用,版本可写可不写,建议写有利于维护系统--> <artifactId>tsgdemo</artifactId> <version>0.0.1-SNAPSHOT</version> <!--打包形式--> <packaging&…...
python+django高校师生健康信息管理系统pycharm
管理员功能模块 4.1登录页面 管理员登录,通过填写注册时输入的用户名、密码、角色进行登录,如图所示。 4.2系统首页 管理员登录进入师生健康信息管理系统可以查看个人中心、学生管理、教师管理、数据收集管理、问卷分类管理、疫情问卷管理、问卷调查管理…...
CUDA中的流序内存分配
文章目录CUDA中的流序内存分配1. Introduction2. Query for Support3. API Fundamentals (cudaMallocAsync and cudaFreeAsync)4. Memory Pools and the cudaMemPool_t注意:设备的内存池当前将是该设备的本地。因此,在不指定内存池的情况下进行分配将始终…...
开源、低成本的 Xilinx FPGA 下载器(高速30MHz)
目前主流的Xilinx下载器主要有两种:一种是Xilinx官方出品的Xilinx Platfom Cable USB,还有一个就是Xilinx的合作伙伴Digilent开发的JTAG-HS3 Programming Cable。 JTAG-HS系列最大支持30MHz下载速度,基于FTDI的FT2232方案。 JTAG-HS系列对比…...
Maven专题总结
1. 什么是Maven Maven 是一个项目管理工具,它包含了一个项目对象模型 (POM: Project Object Model),一组标准集合,一个项目生命周期(Project Lifecycle),一个依赖管理系统(Dependency Management System),和…...
谷粒商城--SPU和SKU
目录 1.SPU和SKU概念 2.表的关系理解 3.导入前端代码 4.完善后端接口 5.属性分组详情 6.规格参数详情 7. 销售属性详情 8.分组与属性关联 9.发布商品 10.仓库服务 1.SPU和SKU概念 SPU:standard product unit(标准化产品单元):是商品信息聚合的…...
二叉树OJ题(上)
✅每日一练:100. 相同的树 - 力扣(LeetCode) 题目的意思是俩棵树的结构不仅要相同,而且每个节点的值还要相同,如果满足上面2个条件,则成立! 解题思路: 从三个方面去考虑࿱…...
第一章 PDF语法
第一章 PDF语法PDF ObjectsNull ObjectsBoolean ObjectsNumeric ObjectsName ObjectsString ObjectsArray ObjectsDictionary ObjectsName treesNumber treesStream ObjectsDirect versus Indirect ObjectsFile StructureWhite-SpaceThe Four Sections of a PDFHeaderTrailerBo…...
网站推广 济南/湘潭网站设计外包服务
GUI程序的基本结构 基本结构如下: # 导入需要的包 from PyQt5.Qt import * import sysapp QApplication(sys.argv) #创建一个应用程序(比不可少的)代码主功能模块区 #控件操作#窗口显示 #开始执行应用程序,并进入消息循环 sys…...
实训做网站收获/正规接单赚佣金的平台
芯片设计进阶之路——门控时钟低功耗深入理解(二)------------------------------------------版权声明:本文作者: 烓围玮未。 主要从事ISP/MIPI/SOC/车规芯片设计首发于知乎专栏:芯片设计进阶之路微信公众号ÿ…...
wordpress更换百度编辑器/站长平台
关键词:学习力、生产力、笔记本软件、surface使用指南引入:在信息化迅速发展的今天,智能手机、计算机已经成为人们必不可少的工具。要想专注于办公学习,一个好的载体必不可少,所以本文集中讲一下我个人对于笔记本电脑或…...
济南网站建设直播/seo网站排名优化公司
理解 C# 项目 csproj 文件格式的本质和编译流程 2018年05月19日 07:58:23 walter lv 阅读数 1901更多 所属专栏: NuGet .NET 编译过程 版权声明:本作品采用知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议进行许可。欢迎转载、使用、重新发…...
怎么做网站写手/百度惠生活推广怎么收费
一,读书列表 1,<简明python教程>,电子版。。。python基础,在2月1日前看完并消化 2,<鸟哥的linux私房菜-基础篇>,电子版(纸质的书,也太贵了,又厚),…...
靠谱网站建设公司怎么选/品牌推广策略包括哪些内容
一. WEB安全技术产生原因 早期:万维网(World Wide Web)仅有Web站点构成,这些站点基本上是包含静态文档的信息库。这种信息流仅由服务器向浏览器单向传送。多数站点并不验证用户的合法性。 如今:已与早期的…...