实战!聊聊工作中使用了哪些设计模式

实战!聊聊工作中使用了哪些设计模式

策略模式

业务场景

  • 假设有这样的业务场景,大数据系统把文件推送过来,根据不同类型采取不同的解析方式。多数的小伙伴就会写出以下的代码:

  • if(type=="A"){//按照A格式解析}else if(type=="B"){//按B格式解析
    }else{//按照默认格式解析
    }
    
  • 这个代码可能会存在哪些问题呢

  • 如果分支变多,这里的代码就会变得臃肿,难以维护,可读性低

  • 如果你需要接入一种新的解析类型,那只能在原有代码上修改

  • 说得专业一点的话,就是以上代码,违背了面向对象编程的开闭原则以及单一原则

    • 开闭原则(对于扩展是开放的,但是对于修改是封闭的):增加或者删除某个逻辑,都需要修改到原来代码
    • 单一原则(规定一个类应该只有一个发生变化的原因):修改任何类型的分支逻辑代码,都需要改动当前类的代码。
    • 如果你的代码就是酱紫:有多个if...else等条件分支,并且每个条件分支,可以封装起来替换的,我们就可以使用策略模式来优化。

策略模式定义

  • 策略模式定义了算法族,分别封装起来,让它们之间可以相互替换,此模式让算法的变化独立于使用算法的的客户。这个策略模式的定义是不是有点抽象呢?那我们来看点通俗易懂的比喻:
  • 假设你跟不同性格类型的小姐姐约会,要用不同的策略,有的请电影比较好,有的则去吃小吃效果不错,有的去逛街买买买最合适。当然,目的都是为了得到小姐姐的芳心,请看电影、吃小吃、逛街就是不同的策略。
  • 策略模式针对一组算法,将每一个算法封装到具有共同接口的独立的类中,从而使得它们可以相互替换。

策略模式使用

  • 策略模式怎么使用呢?酱紫实现的:
    • 一个接口或者抽象类,里面两个方法(一个方法匹配类型,一个可替换的逻辑实现方法)
    • 不同策略的差异化实现(就是说,不同策略的实现类)
    • 使用策略模式

一个接口,两个方法

  • public interface IFileStrategy {//属于哪种文件解析类型FileTypeResolveEnum gainFileType();//封装的公用算法(具体的解析方法)void resolve(Object objectparam);
    }
    

不同策略的差异化实现

  • A 类型策略具体实现

  • @Component
    public class AFileResolve implements IFileStrategy {@Overridepublic FileTypeResolveEnum gainFileType() {return FileTypeResolveEnum.File_A_RESOLVE;}@Overridepublic void resolve(Object objectparam) {logger.info("A 类型解析文件,参数:{}",objectparam);//A类型解析具体逻辑}
    }
    
  • B 类型策略具体实现

  • @Component
    public class BFileResolve implements IFileStrategy {@Overridepublic FileTypeResolveEnum gainFileType() {return FileTypeResolveEnum.File_B_RESOLVE;}@Overridepublic void resolve(Object objectparam) {logger.info("B 类型解析文件,参数:{}",objectparam);//B类型解析具体逻辑}
    }
    
  • 默认类型策略具体实现

  • @Component
    public class DefaultFileResolve implements IFileStrategy {@Overridepublic FileTypeResolveEnum gainFileType() {return FileTypeResolveEnum.File_DEFAULT_RESOLVE;}@Overridepublic void resolve(Object objectparam) {logger.info("默认类型解析文件,参数:{}",objectparam);//默认类型解析具体逻辑}
    }
    

使用策略模式

  • 如何使用呢?我们借助spring的生命周期,使用ApplicationContextAware接口,把对用的策略,初始化到map里面。然后对外提供resolveFile方法即可。

  • /***  @author 公众号:捡田螺的小男孩*/
    @Component
    public class StrategyUseService implements ApplicationContextAware{private Map<FileTypeResolveEnum, IFileStrategy> iFileStrategyMap = new ConcurrentHashMap<>();public void resolveFile(FileTypeResolveEnum fileTypeResolveEnum, Object objectParam) {IFileStrategy iFileStrategy = iFileStrategyMap.get(fileTypeResolveEnum);if (iFileStrategy != null) {iFileStrategy.resolve(objectParam);}}//把不同策略放到map@Overridepublic void setApplicationContext(ApplicationContext applicationContext) throws BeansException {Map<String, IFileStrategy> tmepMap = applicationContext.getBeansOfType(IFileStrategy.class);tmepMap.values().forEach(strategyService -> iFileStrategyMap.put(strategyService.gainFileType(), strategyService));}
    }
    

责任链模式

业务场景

  • 我们来看一个常见的业务场景,下订单。下订单接口,基本的逻辑,一般有参数非空校验、安全校验、黑名单校验、规则拦截等等。很多伙伴会使用异常来实现:

  • public class Order {public void checkNullParam(Object param){//参数非空校验throw new RuntimeException();}public void checkSecurity(){//安全校验throw new RuntimeException();}public void checkBackList(){//黑名单校验throw new RuntimeException();}public void checkRule(){//规则拦截throw new RuntimeException();}public static void main(String[] args) {Order order= new Order();try{order.checkNullParam();order.checkSecurity ();order.checkBackList();order2.checkRule();System.out.println("order success");}catch (RuntimeException e){System.out.println("order fail");}}
    }
    
  • 这段代码使用了异常来做逻辑条件判断,如果后续逻辑越来越复杂的话,会出现一些问题:如异常只能返回异常信息,不能返回更多的字段,这时候需要自定义异常类

  • 并且,阿里开发手册规定:禁止用异常做逻辑判断

  • 【强制】 异常不要用来做流程控制,条件控制。 说明:异常设计的初衷是解决程序运行中的各种意外情况,且异常的处理效率比条件判断方式要低很多。

  • 如何优化这段代码呢?可以考虑责任链模式

责任链模式定义

  • 当你想要让一个以上的对象有机会能够处理某个请求的时候,就使用责任链模式

  • 责任链模式为请求创建了一个接收者对象的链。执行链上有多个对象节点,每个对象节点都有机会(条件匹配)处理请求事务,如果某个对象节点处理完了,就可以根据实际业务需求传递给下一个节点继续处理或者返回处理完毕。这种模式给予请求的类型,对请求的发送者和接收者进行解耦。

  • 责任链模式实际上是一种处理请求的模式,它让多个处理器(对象节点)都有机会处理该请求,直到其中某个处理成功为止。责任链模式把多个处理器串成链,然后让请求在链上传递:

  • [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-o2cBhb5L-1690803040616)(C:\Users\quyanliang\AppData\Roaming\Typora\typora-user-images\1690802238806.png)]

  • 打个比喻:

  • 假设你晚上去上选修课,为了可以走点走,坐到了最后一排。来到教室,发现前面坐了好几个漂亮的小姐姐,于是你找张纸条,写上:“你好, 可以做我的女朋友吗?如果不愿意请向前传”。纸条就一个接一个的传上去了,后来传到第一排的那个妹子手上,她把纸条交给老师,听说老师40多岁未婚…

责任链模式使用

  • 责任链模式怎么使用呢?
    • 一个接口或者抽象类
    • 每个对象差异化处理
    • 对象链(数组)初始化(连起来)

一个接口或者抽象类

  • 这个接口或者抽象类,需要:

    • 有一个指向责任下一个对象的属性
    • 一个设置下一个对象的set方法
    • 给子类对象差异化实现的方法(如以下代码的doFilter方法)
  • /***  关注公众号:捡田螺的小男孩*/
    public abstract class AbstractHandler {//责任链中的下一个对象private AbstractHandler nextHandler;/*** 责任链的下一个对象*/public void setNextHandler(AbstractHandler nextHandler){this.nextHandler = nextHandler;}/*** 具体参数拦截逻辑,给子类去实现*/public void filter(Request request, Response response) {doFilter(request, response);if (getNextHandler() != null) {getNextHandler().filter(request, response);}}public AbstractHandler getNextHandler() {return nextHandler;}abstract void doFilter(Request filterRequest, Response response);}
    

每个对象差异化处理

  • 责任链上,每个对象的差异化处理,如本小节的业务场景,就有参数校验对象、安全校验对象、黑名单校验对象、规则拦截对象

  • /*** 参数校验对象**/
    @Component
    @Order(1) //顺序排第1,最先校验
    public class CheckParamFilterObject extends AbstractHandler {@Overridepublic void doFilter(Request request, Response response) {System.out.println("非空参数检查");}
    }/***  安全校验对象*/
    @Component
    @Order(2) //校验顺序排第2
    public class CheckSecurityFilterObject extends AbstractHandler {@Overridepublic void doFilter(Request request, Response response) {//invoke Security checkSystem.out.println("安全调用校验");}
    }
    /***  黑名单校验对象*/
    @Component
    @Order(3) //校验顺序排第3
    public class CheckBlackFilterObject extends AbstractHandler {@Overridepublic void doFilter(Request request, Response response) {//invoke black list checkSystem.out.println("校验黑名单");}
    }/***  规则拦截对象*/
    @Component
    @Order(4) //校验顺序排第4
    public class CheckRuleFilterObject extends AbstractHandler {@Overridepublic void doFilter(Request request, Response response) {//check ruleSystem.out.println("check rule");}
    }
    

对象链连起来(初始化)&& 使用

  • @Component("ChainPatternDemo")
    public class ChainPatternDemo {//自动注入各个责任链的对象@Autowiredprivate List<AbstractHandler> abstractHandleList;private AbstractHandler abstractHandler;//spring注入后自动执行,责任链的对象连接起来@PostConstructpublic void initializeChainFilter(){for(int i = 0;i<abstractHandleList.size();i++){if(i == 0){abstractHandler = abstractHandleList.get(0);}else{AbstractHandler currentHander = abstractHandleList.get(i - 1);AbstractHandler nextHander = abstractHandleList.get(i);currentHander.setNextHandler(nextHander);}}}//直接调用这个方法使用public Response exec(Request request, Response response) {abstractHandler.filter(request, response);return response;}public AbstractHandler getAbstractHandler() {return abstractHandler;}public void setAbstractHandler(AbstractHandler abstractHandler) {this.abstractHandler = abstractHandler;}
    }
    
  • 运行结果如下:

  • 非空参数检查
    安全调用校验
    校验黑名单
    check rule
    

模板方法模式

业务场景

  • 假设我们有这么一个业务场景:内部系统不同商户,调用我们系统接口,去跟外部第三方系统交互(http方式)。走类似这么一个流程,如下:

  • [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-WfHBHIaV-1690803040618)(C:\Users\quyanliang\AppData\Roaming\Typora\typora-user-images\1690802358215.png)]

  • 一个请求都会经历这几个流程:

    • 查询商户信息
    • 对请求报文加签
    • 发送http请求出去
    • 对返回的报文验签
  • 这里,有的商户可能是走代理出去的,有的是走直连。假设当前有A,B商户接入,不少伙伴可能这么实现,伪代码如下: \

  • // 商户A处理句柄
    CompanyAHandler implements RequestHandler {Resp hander(req){//查询商户信息queryMerchantInfo();//加签signature();//http请求(A商户假设走的是代理)httpRequestbyProxy()//验签verify();}
    }
    // 商户B处理句柄
    CompanyBHandler implements RequestHandler {Resp hander(Rreq){//查询商户信息queryMerchantInfo();//加签signature();// http请求(B商户不走代理,直连)httpRequestbyDirect();// 验签verify(); }
    }
    
  • 假设新加一个C商户接入,你需要再实现一套这样的代码。显然,这样代码就重复了,一些通用的方法,却在每一个子类都重新写了这一方法

  • 如何优化呢?可以使用模板方法模式

模板方法模式定义

  • 定义一个操作中的算法的骨架流程,而将一些步骤延迟到子类中,使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤。它的核心思想就是:定义一个操作的一系列步骤,对于某些暂时确定不下来的步骤,就留给子类去实现,这样不同的子类就可以定义出不同的步骤。
  • 打个通俗的比喻:
  • 模式举例:追女朋友要先“牵手”,再“拥抱”,再“接吻”, 再“拍拍…额…手”。至于具体你用左手还是右手牵,无所谓,但是整个过程,定了一个流程模板,按照模板来就行。

模板方法使用

  • 一个抽象类,定义骨架流程(抽象方法放一起)
  • 确定的共同方法步骤,放到抽象类(去除抽象方法标记)
  • 不确定的步骤,给子类去差异化实现
  • 我们继续那以上的举例的业务流程例子,来一起用 模板方法优化一下哈:

一个抽象类,定义骨架流程

  • 因为一个个请求经过的流程为一下步骤:

    • 查询商户信息
    • 对请求报文加签
    • 发送http请求出去
    • 对返回的报文验签
  • 所以我们就可以定义一个抽象类,包含请求流程的几个方法,方法首先都定义为抽象方法哈:

  • /*** 抽象类定义骨架流程(查询商户信息,加签,http请求,验签)*/
    abstract class AbstractMerchantService  { //查询商户信息abstract queryMerchantInfo();//加签abstract signature();//http 请求abstract httpRequest();// 验签abstract verifySinature();}
    

确定的共同方法步骤,放到抽象类

  • abstract class AbstractMerchantService  { //模板方法流程Resp handlerTempPlate(req){//查询商户信息queryMerchantInfo();//加签signature();//http 请求httpRequest();// 验签verifySinature();}// Http是否走代理(提供给子类实现)abstract boolean isRequestByProxy();
    }
    

不确定的步骤,给子类去差异化实现

  • 因为是否走代理流程是不确定的,所以给子类去实现。

  • 商户A的请求实现:

  • CompanyAServiceImpl extends AbstractMerchantService{Resp hander(req){return handlerTempPlate(req);}//走http代理的boolean isRequestByProxy(){return true;}
    
  • 商户B的请求实现:

  • CompanyBServiceImpl extends AbstractMerchantService{Resp hander(req){return handlerTempPlate(req);}//公司B是不走代理的boolean isRequestByProxy(){return false;}

观察者模式

业务场景

  • 登陆注册应该是最常见的业务场景了。就拿注册来说事,我们经常会遇到类似的场景,就是用户注册成功后,我们给用户发一条消息,又或者发个邮件等等,因此经常有如下的代码:

  • void register(User user){insertRegisterUser(user);sendIMMessage();sendEmail();
    }
    
  • 这块代码会有什么问题呢? 如果产品又加需求:现在注册成功的用户,再给用户发一条短信通知。于是你又得改register方法的代码了。。。这是不是违反了开闭原则啦。

  • void register(User user){insertRegisterUser(user);sendIMMessage();sendMobileMessage();sendEmail();
    }
    
  • 并且,如果调发短信的接口失败了,是不是又影响到用户注册了?!这时候,是不是得加个异步方法给通知消息才好。。。

  • 实际上,我们可以使用观察者模式优化。

观察者模式定义

  • 观察者模式定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被完成业务的更新。
  • 观察者模式属于行为模式,一个对象(被观察者)的状态发生改变,所有的依赖对象(观察者对象)都将得到通知,进行广播通知。它的主要成员就是观察者和被观察者
    • 被观察者(Observerable):目标对象,状态发生变化时,将通知所有的观察者。
    • 观察者(observer):接受被观察者的状态变化通知,执行预先定义的业务。
  • 使用场景: 完成某件事情后,异步通知场景。如,登陆成功,发个IM消息等等。

观察者模式使用

  • 观察者模式实现的话,还是比较简单的。
    • 一个被观察者的类Observerable ;
    • 多个观察者Observer ;
    • 观察者的差异化实现
    • 经典观察者模式封装:EventBus实战

一个被观察者的类Observerable 和 多个观察者Observer

  • public class Observerable {private List<Observer> observers = new ArrayList<Observer>();private int state;public int getState() {return state;}public void setState(int state) {notifyAllObservers();}//添加观察者public void addServer(Observer observer){observers.add(observer);      }//移除观察者public void removeServer(Observer observer){observers.remove(observer);      }//通知public void notifyAllObservers(int state){if(state!=1){System.out.println(“不是通知的状态”);return ;}for (Observer observer : observers) {observer.doEvent();}}  
    }
    

观察者的差异化实现

  •  //观察者interface Observer {  void doEvent();  
    }  
    //Im消息
    IMMessageObserver implements Observer{void doEvent(){System.out.println("发送IM消息");}
    }//手机短信
    MobileNoObserver implements Observer{void doEvent(){System.out.println("发送短信消息");}
    }
    //EmailNo
    EmailObserver implements Observer{void doEvent(){System.out.println("发送email消息");}
    }
    

EventBus实战

  • 自己搞一套观察者模式的代码,还是有点小麻烦。实际上,Guava EventBus 就封装好了,它 提供一套基于注解的事件总线,api可以灵活的使用,爽歪歪。

  • 我们来看下EventBus的实战代码哈,首先可以声明一个EventBusCenter类,它类似于以上被观察者那种角色Observerable

  • public class EventBusCenter {private static EventBus eventBus = new EventBus();private EventBusCenter() {}public static EventBus getInstance() {return eventBus;}//添加观察者public static void register(Object obj) {eventBus.register(obj);}//移除观察者public static void unregister(Object obj) {eventBus.unregister(obj);}//把消息推给观察者public static void post(Object obj) {eventBus.post(obj);}
    }
    
  • 然后再声明观察者EventListener

  • public class EventListener {@Subscribe //加了订阅,这里标记这个方法是事件处理方法  public void handle(NotifyEvent notifyEvent) {System.out.println("发送IM消息" + notifyEvent.getImNo());System.out.println("发送短信消息" + notifyEvent.getMobileNo());System.out.println("发送Email消息" + notifyEvent.getEmailNo());}
    }//通知事件类
    public class NotifyEvent  {private String mobileNo;private String emailNo;private String imNo;public NotifyEvent(String mobileNo, String emailNo, String imNo) {this.mobileNo = mobileNo;this.emailNo = emailNo;this.imNo = imNo;}}
    
  • 使用demo测试:

  • public class EventBusDemoTest {public static void main(String[] args) {EventListener eventListener = new EventListener();EventBusCenter.register(eventListener);EventBusCenter.post(new NotifyEvent("13372817283", "123@qq.com", "666"));}
    }
    
  • 运行结果:

  • 发送IM消息666
    发送短信消息13372817283
    发送Email消息123@qq.com
    

工厂模式

业务场景

  • 工厂模式一般配合策略模式一起使用。用来去优化大量的if...else...switch...case...条件语句。

  • 我们就取第一小节中策略模式那个例子吧。根据不同的文件解析类型,创建不同的解析对象

  •  IFileStrategy getFileStrategy(FileTypeResolveEnum fileType){IFileStrategy  fileStrategy ;if(fileType=FileTypeResolveEnum.File_A_RESOLVE){fileStrategy = new AFileResolve();}else if(fileType=FileTypeResolveEnum.File_A_RESOLV){fileStrategy = new BFileResolve();}else{fileStrategy = new DefaultFileResolve();}return fileStrategy;}
    
  • 其实这就是工厂模式,定义一个创建对象的接口,让其子类自己决定实例化哪一个工厂类,工厂模式使其创建过程延迟到子类进行。

  • 策略模式的例子,没有使用上一段代码,而是借助spring的特性,搞了一个工厂模式,哈哈,小伙伴们可以回去那个例子细品一下,我把代码再搬下来,小伙伴们再品一下吧:

  • /***  @author 公众号:捡田螺的小男孩*/
    @Component
    public class StrategyUseService implements ApplicationContextAware{private Map<FileTypeResolveEnum, IFileStrategy> iFileStrategyMap = new ConcurrentHashMap<>();//把所有的文件类型解析的对象,放到map,需要使用时,信手拈来即可。这就是工厂模式的一种体现啦@Overridepublic void setApplicationContext(ApplicationContext applicationContext) throws BeansException {Map<String, IFileStrategy> tmepMap = applicationContext.getBeansOfType(IFileStrategy.class);tmepMap.values().forEach(strategyService -> iFileStrategyMap.put(strategyService.gainFileType(), strategyService));}
    }
    

使用工厂模式

  • 定义工厂模式也是比较简单的:
    • 一个工厂接口,提供一个创建不同对象的方法。
    • 其子类实现工厂接口,构造不同对象
    • 使用工厂模式

一个工厂接口

  • interface IFileResolveFactory{void resolve();
    }
    

不同子类实现工厂接口

  • class AFileResolve implements IFileResolveFactory{void resolve(){System.out.println("文件A类型解析");}
    }class BFileResolve implements IFileResolveFactory{void resolve(){System.out.println("文件B类型解析");}
    }class DefaultFileResolve implements IFileResolveFactory{void resolve(){System.out.println("默认文件类型解析");}
    }
    

使用工厂模式

  • //构造不同的工厂对象
    IFileResolveFactory fileResolveFactory;
    if(fileType=“A”){fileResolveFactory = new AFileResolve();
    }else if(fileType=“B”){fileResolveFactory = new BFileResolve();}else{fileResolveFactory = new DefaultFileResolve();
    }fileResolveFactory.resolve();
    
  • 一般情况下,对于工厂模式,你不会看到以上的代码。工厂模式会跟配合其他设计模式如策略模式一起出现的。

单例模式

业务场景

  • 单例模式,保证一个类仅有一个实例,并提供一个访问它的全局访问点。 I/O与数据库的连接,一般就用单例模式实现de的。Windows里面的Task Manager(任务管理器)也是很典型的单例模式。

  • 来看一个单例模式的例子

  • public class LanHanSingleton {private static LanHanSingleton instance;private LanHanSingleton(){}public static LanHanSingleton getInstance(){if (instance == null) {instance = new LanHanSingleton();}return instance;}}
    

单例模式的经典写法

  • 其实单例模式还有有好几种实现方式,如饿汉模式,双重校验锁,静态内部类,枚举等实现方式

饿汉模式

  • public class EHanSingleton {private static EHanSingleton instance = new EHanSingleton();private EHanSingleton(){      }public static EHanSingleton getInstance() {return instance;}
    }
    
  • 饿汉模式,它比较饥饿、比较勤奋,实例在初始化的时候就已经建好了,不管你后面有没有用到,都先新建好实例再说。这个就没有线程安全的问题,但是呢,浪费内存空间呀。

双重校验锁

  • public class DoubleCheckSingleton {private static DoubleCheckSingleton instance;private DoubleCheckSingleton() { }public static DoubleCheckSingleton getInstance(){if (instance == null) {synchronized (DoubleCheckSingleton.class) {if (instance == null) {instance = new DoubleCheckSingleton();}}}return instance;}
    }
    
  • 双重校验锁实现的单例模式,综合了懒汉式和饿汉式两者的优缺点。以上代码例子中,在synchronized关键字内外都加了一层 if 条件判断,这样既保证了线程安全,又比直接上锁提高了执行效率,还节省了内存空间。

静态内部类

  • public class InnerClassSingleton {private static class InnerClassSingletonHolder{private static final InnerClassSingleton INSTANCE = new InnerClassSingleton();}private InnerClassSingleton(){}public static final InnerClassSingleton getInstance(){return InnerClassSingletonHolder.INSTANCE;}
    }
    
  • 静态内部类的实现方式,效果有点类似双重校验锁。但这种方式只适用于静态域场景,双重校验锁方式可在实例域需要延迟初始化时使用。

枚举

  • public enum SingletonEnum {INSTANCE;public SingletonEnum getInstance(){return INSTANCE;}
    }
    

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

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

相关文章

Electron逆向调试

复杂程序处理方式&#xff1a; 复杂方式通过 调用窗口 添加命令行参数 启动允许调用&#xff0c;就可以实现调试发布环境的electron程序。 断点调试分析程序的走向&#xff0c;程序基本上会有混淆代码处理&#xff0c; 需要调整代码格式&#xff0c;处理程序。

基于 Docker 的深度学习环境:Windows 篇

本篇文章&#xff0c;我们聊聊如何在 Windows 环境下使用 Docker 作为深度学习环境&#xff0c;以及快速运行 SDXL 1.0 正式版&#xff0c;可能是目前网上比较简单的 Docker、WSL2 配置教程啦。 写在前面 早些时候&#xff0c;写过一篇《基于 Docker 的深度学习环境&#xff…

Hbase基础概念

HBase 一、HBase的数据模型1.HBase数据存储结构2.HBase存储概念3.HBase基本架构 二、HBase Shell1.DDL(Data Definition Language)1.namespace2.table 2.DML&#xff08;Data Manipulation Language&#xff09;1.写入数据2.读取数据3.删除数据 三、HBase组成架构1. Master架构…

STM32 CubeMX 定时器(普通模式和PWM模式)

STM32 CubeMX STM32 CubeMX 定时器&#xff08;普通模式和PWM模式&#xff09; STM32 CubeMXSTM32 CubeMX 普通模式一、STM32 CubeMX 设置二、代码部分STM32 CubeMX PWM模式一、STM32 CubeMX 设置二、代码部分总结 STM32 CubeMX 普通模式 一、STM32 CubeMX 设置 二、代码部分 …

使用Pytest生成HTML测试报告

背景 最近开发有关业务场景的功能时&#xff0c;涉及的API接口比较多&#xff0c;需要自己模拟多个业务场景的自动化测试&#xff08;暂时不涉及性能测试&#xff09;&#xff0c;并且在每次测试完后能够生成一份测试报告。 考虑到日常使用Python自带的UnitTest&#xff0c;所…

【JVM】详细解析java创建对象的具体流程

目录 一、java创建对象的几种方式 1.1、使用new关键字 1.2、反射创建对象 1.2.1、Class.newInstance创建对象 1.2.2、调用构造器再去创建对象Constructor.newInstance 1.3、clone实现 1.4、反序列化 二、创建对象的过程 2.1、分配空间的方式 1、指针碰撞 2、空闲列表 …

ElementUI 实现动态表单数据校验(已解决)

文章目录 &#x1f34b;前言&#xff1a;&#x1f34d;正文1、探讨需求2、查阅相关文档&#xff08;[element官网](https://element.eleme.cn/#/zh-CN/component/form)&#xff09;官方动态增减表单项示例3、需求完美解决4、注意事项 &#x1f383;专栏分享&#xff1a; &#…

【Linux基础】WSL安装Ubuntu

说明 本文使用的Windows环境是Windows 11 专业版。 WSL现在有二代WSL2&#xff0c;后续都通过WSL2来安装Linux&#xff0c;使用的是Ubuntu发行版&#xff0c;版本是20.04。 安装过程使用了PowerShell&#xff0c;且是管理员权限打开的。 参考适用于 Linux 的 Windows 子系统…

【深度学习】生成对抗网络Generative Adversarial Nets

序言 本文是GAN网络的原始论文&#xff0c;发表于2014年&#xff0c;我们知道&#xff0c;对抗网络是深度学习中&#xff0c;CNN基础上的一大进步&#xff1b; 它最大的好处是&#xff0c;让网络摆脱训练成“死模型”到固定场所处去应用&#xff0c;而是对于变化的场景&#xf…

16位S912ZVML32F3MKH、S912ZVML31F1WKF、S912ZVML31F1MKH混合信号MCU,适用于汽车和工业电机控制应用。

S12 MagniV微控制器是易于使用且高度集成的混合信号MCU&#xff0c;非常适合用于汽车和工业应用。S12 MagniV MCU提供单芯片解决方案&#xff0c;是基于成熟的S12技术的完整系统级封装 (SiP) 解决方案&#xff0c;在整个产品组合内软件和工具都兼容。 S12 MagniV系统级封装 (S…

通过IDEA发送QQ邮箱信息

先创建一个普通的Maven项目&#xff0c;我就不演示啦&#xff0c;个人博客已经写过~[创建一个maven项目]。 项目创建成功后&#xff0c;引人Maven依赖&#xff0c;如下: <dependencies><dependency><groupId>org.apache.commons</groupId><artifact…

在k8s集群内搭建Prometheus监控平台

基本架构 Prometheus由SoundCloud发布&#xff0c;是一套由go语言开发的开源的监控&报警&时间序列数据库的组合。 Prometheus的基本原理是通过HTTP协议周期性抓取被监控组件的状态&#xff0c;任意组件只要提供对应的HTTP接口就可以接入监控。不需要任何SDK或者其他的…

大数据_Hadoop_Parquet数据格式详解

之前有面试官问到了parquet的数据格式&#xff0c;下面对这种格式做一个详细的解读。 参考链接 &#xff1a; 列存储格式Parquet浅析 - 简书 Parquet 文件结构与优势_parquet文件_KK架构的博客-CSDN博客 Parquet文件格式解析_parquet.block.size_davidfantasy的博客-CSDN博…

Redis学习路线(6)—— Redis的分布式锁

一、分布式锁的模型 &#xff08;一&#xff09;悲观锁&#xff1a; 认为线程安全问题一定会发生&#xff0c;因此在操作数据之前先获取锁&#xff0c;确保线程串行执行。例如Synchronized、Lock都属于悲观锁。 优点&#xff1a; 简单粗暴缺点&#xff1a; 性能略低 &#x…

Qt 4. 发布exe

把ex2.exe放在H盘Ex2文件夹下&#xff0c;执行 H:\Ex2>windeployqt ex2.exe H:\Ex2>windeployqt ex2.exe H:\Ex2\ex2.exe 64 bit, release executable Adding Qt5Svg for qsvgicon.dll Skipping plugin qtvirtualkeyboardplugin.dll due to disabled dependencies (Qt5…

go 查询采购单设备事项[小示例]V2-两种模式{严格,包含模式}

第一版&#xff1a; https://mp.csdn.net/mp_blog/creation/editor/131979385 第二版&#xff1a; 优化内容&#xff1a; 检索数据的两种方式&#xff1a; 1.严格模式--找寻名称是一模一样的内容&#xff0c;在上一个版本实现了 2.包含模式&#xff0c;也就是我输入检索关…

舌体分割的初步展示应用——依托Streamlit搭建demo

1 前言 去年在社区发布了有关中医舌象诊断的博文&#xff0c;其中舌象识别板块受到了极高的关注和关注。&#x1f60a;最近&#xff0c;我接触到了Python的Streamlit库&#xff0c;它可以帮助数据相关从业人员轻松搭建数据看板。本文将介绍如何使用Streamlit构建舌体分割的演示…

算法与数据结构-二分查找

文章目录 什么是二分查找二分查找的时间复杂度二分查找的代码实现简单实现&#xff1a;不重复有序数组查找目标值变体实现&#xff1a;查找第一个值等于给定值的元素变体实现&#xff1a;查找最后一个值等于给定值的元素变体实现&#xff1a;查找最后一个小于给定值的元素变体实…

大龄青年的浙大MBA读书梦——提面优秀190+的上岸经验分享

时间如白驹过隙&#xff0c;三十年的岁月也转瞬即逝&#xff0c;回首过往这三十年的人生路&#xff0c;没有大起大落&#xff0c;一直都是相对比较平稳。但这几年疫情原因&#xff0c;公司效益不好&#xff0c;不仅我们公司整个行业也都在裁员&#xff0c;为了让自己更具备竞争…

flask数据库操作

本文将详细介绍在Flask Web应用中如何设计数据库模型,并使用Flask-SQLAlchemy等扩展进行数据库操作的最佳实践。内容涵盖数据模型设计,ORM使用,关系映射,查询方法,事务处理等方面。通过本文,您可以掌握Flask数据库应用的基本知识。 Flask作为一个流行的Python Web框架,提供了高…