设计模式(一)

news2024/11/26 4:38:31

1、适配器模式

(1)概述

  • 适配器中有一个适配器包装类Adapter,其包装的对象为适配者Adaptee,适配器作用就是将客户端请求转化为调用适配者中的接口;
  • 当调用适配器中的方法时,适配器内部会调用适配者类的方法,这个调用对客户端是透明,实现了不同接口之间由于不兼容的类,可以相互调用;

(2)对象适配器

  • Target(目标抽象类):可以是一个抽象类或接口,该类为客户端所需要的接口;
  • Adapter(适配器类):Adapter可以调用另外一个接口,对Target和Adaptee进行适配,Target通过Adapter可以调用Adaptee中的业务逻辑,对客户端是透明的;
  • Adaptee(适配者类):定义了一个已经存在的接口,适配者类一般是一个具体的类,包含了客户需要调用的业务方法;
  • Adapter和Adaptee是关联关系;

//适配器
public class Adapter implements Target{
    private MySQLConnect mySQLConnect;//适配者对象

    public Adapter(MySQLConnect mySQLConnect){
        this.mySQLConnect=mySQLConnect;
    }

    @Override
    public void connect() {
        mySQLConnect.mysqlConnect();
    }
}
public interface Target {
    public void connect();
}
//适配者
public class MySQLConnect {
    public void mysqlConnect(){
        System.out.println("数据库链接配置");
    }
}
//测试
public class Main {
    public static void main(String[] args) {
        Target target=new Adapter(new MySQLConnect());
        target.connect();
    }
}

(3)类适配器

  • 适配器和适配者之间的关系为继承;
  • 适配器实现了Target接口,继承了Adapteee类;
  • 当Target不是接口,而是抽象类,则无法使用类适配器,当Adaptee类被final修饰,也不能使用类适配器;
//适配器类,其他代码和上一样
public class Adapter extends MySQLConnect implements Target{
    @Override
    public void connect() {
        mysqlConnect();
    }
}

(3)缺省适配器

  • ServiceInterface(适配者接口):为一个接口,实现大量方法;
  • AbstractServiceClass(缺省适配器类):实现了适配者接口中所有方法,使用空方法形式;
  • ConcreteServiceClass(业务类):为缺省适配器的子类,在没有适配器之前,该类需要实现ServiceInterface中所有方法,引入适配器类后,只需要继承适配器类,实现对应的方法即可;
public interface ServiceInterface {
    public void print();
    public void eat();
    public void smell();
}
public class AbstractService implements ServiceInterface{//缺省适配器
    @Override
    public void print() { }
    @Override
    public void eat() { }
    @Override
    public void smell() { }
}
public class ConcreteService extends AbstractService{
    @Override
    public void print() {//重写打印接口
        System.out.println("打印");
    }
}

(4)总结

优点:

  • 目标类和适配者类解耦,通过引入一个适配器类来重用现有的适配者类,无序修改原有代码结构;
  • 增加了类的透明性和复用性,将业务代码封装在适配者类中,对于用户是透明的,同时适配者类可以被多个不同系统调用
  • 灵活性和扩展性好,通过配置文件切换适配器类,可以在原有基础上添加新的适配器类,符合开闭原则;

缺点:

  • 类适配器中只能适配一个适配者类,java不能多继承;
  • 对象适配器,在适配器重置换适配者类比较麻烦,需要先创建一个适配者类的子类,重写需要置换的方法,然后再将适配器适配到这个子类;

使用场景:

  • 系统需要使用已有的接口,而这些接口不符合系统需求,甚至没有源代码;
  • 想创建一个可以重复使用的类,用于一些彼此之间没有太大关联的一些类,包括一些可能在将来引进的类一起工作;

2、工厂方法模式

(1)概述

  • 工厂方法定义一个创建对象的接口,让实现该接口的子类取实例化对象。
  • 工厂方法将对象的实例化延迟到其子类创建;

(2)角色

  • Product(抽象产品):定义产品接口(某个类型产品),是工厂方法模式中,所有创建对象的公共父类;
  • ConcreteProduct(具体产品):实现抽象产品的接口,即某种类型的具体产品,与一个具体工厂一一对应;
  • Factory(抽象工厂):创建对象工厂的接口,声明工厂方法(Factory Method),用于返回一个产品,所有创建对象的工厂类都需要实现该接口;
  • ConcreteFactory(具体工厂):实现抽象工厂的工厂方法,返回一个具体的产品;

(3)实现

public interface Factory {
    public Product create();
}
public class MySQLFactory implements Factory{
    @Override
    public Product create() {
        return new MySQLProduct();
    }
}
public abstract class Factory {//抽象工厂
    public void connect(){//对客户端隐藏调用具体产品的方法
        Product product = this.create();
        product.connect();
    }

    public abstract Product create();
}
public class MySQLFactory extends Factory{//具体工厂
    @Override
    public Product create() {
        return new MySQLProduct();
    }
}
public class Main {
    public static void main(String[] args) {
        Factory factory=new MySQLFactory();//可以通过配置文件配置,进行工厂方法切换
        factory.connect();
    }
}

(4)总结

优点

  • 客户端只需要知道创建对象的工厂方法,工厂方法隐藏具体具体对象被实例化的细节,客户端无需关系对象如何创建,甚至无需关心对象的具体类名;
  • 当需要加入一个新的对象产品时,无需修改原系统,只需要新增一个具体对象类和对应的工厂类即可;

缺点:

  • 每新增一个产品,就需要新增对应的产品类和工厂类,增加系统复杂度,同时由更多类需要被系统加载,会给系统带来一些而外的开销;
  • 引入抽象层,增加系统抽象性和可理解性;

使用场景:

  • 客户端不知道他所需要的类;
  • 抽象工厂类通过子类创建对象;

3、抽象工厂模式

(1)概述

  • 产品等级结构:即产品的继承结构,一个抽象产品,多个相同的产品继承该抽象产品,一个抽象产品与其子类构成一个产品等级结构。如:电视机为抽象类,则海尔电视机,华普电视机,创维电视机为其子类,共同构成一个产品等级结构;
  • 产品族:产品族是由同一个工厂产生的,位于不同产品等级结构的一组产品;
  • 一个工厂负责生产一个产品族(即下图颜色相同的);
  • 抽象工厂会提供一个创建一系列相关或相互依赖的对象的接口,而无需指定他们的具体实现类;

(2)角色

  • AbstractFactory(抽象工厂):声明一些列创建产品族的方法,每一个方法对应一个产品;
  • ConcreteFactory(具体工厂):实现抽象工厂中的方法,用于创建一组具体产品,这些具体产品构成一个产品族,位于一个产品等级结构中;
  • AbstractProduct(抽象产品):为每种产品生成一种接口,在抽象产品中声明了产品所具有的业务方法;
  • ConcreteProduct(具体产品):他定义具体工厂生成的产品对象,实现抽象产品接口中声明的业务方法;

(3)实现

public interface AbstractFactory {//抽象工厂
    public AbstractProductA createProductA();
    public AbstractProductB createProductB();
}
public class ConcreteProduct1 implements AbstractFactory{//具体工厂1
    @Override
    public AbstractProductA createProductA() {
        return new ProductA1();
    }
    @Override
    public AbstractProductB createProductB() {
        return new ProductB1();
    }
}
public class ConcreteProduct2 implements AbstractFactory{//具体工厂2
    @Override
    public AbstractProductA createProductA() {
        return new ProductA2();
    }
    @Override
    public AbstractProductB createProductB() {
        return new ProductB2();
    }
}
public interface AbstractProductA {//抽象产品A
    public void printA();
}
public class ProductA1 implements AbstractProductA{//具体产品A--1
    @Override
    public void printA() {
        System.out.println("产品A类--型号1类型");
    }
}
public class ProductA2 implements AbstractProductA{//具体产品A---2
    @Override
    public void printA() {
        System.out.println("产品A类--型号2类型");
    }
}
public interface AbstractProductB {//抽象产品B
    public void printB();
}
public class ProductB1 implements AbstractProductB{//具体产品B--1
    @Override
    public void printB() {
        System.out.println("产品B类--型号1类型");
    }
}
public class ProductB2 implements AbstractProductB{//具体产品B--2
    @Override
    public void printB() {
        System.out.println("产品B类--型号2类型");
    }
}
public class Main {//测试类
    public static void main(String[] args) {
        System.out.println("工厂1生成对应1号类型的产品族");
        AbstractFactory factory1=new ConcreteProduct1();
        factory1.createProductA().printA();
        factory1.createProductB().printB();

        System.out.println("工厂2生成对应的2号类型的产品族");
        AbstractFactory factory2=new ConcreteProduct2();
        factory2.createProductA().printA();
        factory2.createProductB().printB();
    }
}

(4)总结

优点:

  • 客户端不需要知道产品如何创建,如果需要切换产品,更换一个具体工厂即可;
  • 增加新的产品族十分方便,无需修改原系统,符合开闭原则;

缺点:

  • 添加一个产品等级结构系列时,需要从修改原有系统中的所有工厂方法,不符合开闭原则;

使用场景:

  • 一个系统不依赖对象的创建,组合,客户端无需知道对象如何创建;
  • 系统中有多个产品族,每次只使用一个产品族;
  • 同一个产品族中的产品将在一起使用,同一个产品族的产品可以没有任何关系,但必须是有一总共同约束;

4、装饰器模式

(1)概述

  • 装饰模式可以在不改变原有对象的模式下,增加额外行为;
  • 可以动态给对象增加一些职责;

(2)角色

  • Component(抽象组件):他是具体组件和装饰组件的父类,声明了具体组件实现的业务方法,为客户端提供以一致方式处理装饰前以及装饰后的组件;
  • ConcreteComponent(具体组件):Component的子类,用于定义具体的组件方法,装饰器类可以给他增加额外职责;
  • Decorator(抽象装饰类):Component子类,用于给具体组件添加新的职责,他维护一个指向抽象组件的应用,通过该应用可以调用装饰之前的组件,并通过起子类扩展职责;
  • ConcreteDecorator(具体装饰类):抽象装饰类的子类,负责向具体组件添加新的职责;

(3)实现

public interface Component {//抽象组件
    public void operation();
}
public class ConcreteComponent implements Component{//具体组件
    @Override
    public void operation() {
        System.out.println("组件操作");
    }
}
public class Decorator implements Component{//抽象装饰器
    private Component component;
    public Decorator(Component component){
        this.component=component;
    }
    @Override
    public void operation() {
        component.operation();
    }
}
public class ConcreteDecoratorA extends Decorator{//具体装饰类
    public ConcreteDecoratorA(Component component) {
        super(component);
    }

    @Override
    public void operation() {
        super.operation();
        addState();
    }

    public void addState(){
        System.out.println("添加机器状态");
    }
}
public class ConcreteDecoratorB extends Decorator {//具体装饰类
    public ConcreteDecoratorB(Component component) {
        super(component);
    }

    @Override
    public void operation() {
        super.operation();
        addMoney();
    }

    public void addMoney(){
        System.out.println("加钱,买更多机器投入操作");
    }
}
public class Main {//main方法
    public static void main(String[] args) {
        Component component=new ConcreteComponent();
        System.out.println("装饰器A-----------");
        Decorator decorator=new ConcreteDecoratorA(component);
        decorator.operation();
        System.out.println("装饰器B---------------");
        decorator=new ConcreteDecoratorB(component);
        decorator.operation();
    }
}

(4)总结

优点:

  • 装饰器比继承更加灵活,不会导致类个数急剧增加;
  • 可以动态的扩展一个对象功能,通过配置类可以在运行时选择不同的配置类,从而实现不同行为;
  • 可以对一个对象装饰多次,采用不同1装饰类可以组装出多个不同的行为;
  • 具体的组件类和装饰类可以独立添加,可以根据需要添加新的构建类和组件类,符合开闭原则;

缺点:

  • 会产生大量的小对象,这些小对象随着不断累积,会消耗大量内存;
  • 对于排错,需要多级查找;

使用场景:

  • 在不影响其他对象的情况下,动态,透明的给一个对象添加职责;
  • 系统中存在大量独立的类,不可以使用装饰器模式,否则会产生大量的子类;

5、建造者模式

(1)概述

  • 将一个复杂对象的构建与他的表示分离,使得同样构建过程可以创建不同的表示;
  • 不同的具体建造者定义不同的创建过程,且具体的建造者相互独立,增加新的建造者非常方便;

(2)角色

  • Builder(抽象建造者):他为建造复杂对象的各个部件定义接口,在接口中声明方法中,一类是buildProductX方法,用于构建各个组件,另外一类为getProduct()方法,用于获取构建后的对象;既可以是接口,也可以是抽象类;
  • Concretebuilder(具体建造者):实现Builder接口,实现各个构造组件的方法,并实现返回一个对象的方法;
  • Product(产品):具体的构建对象,包含多个组件,由ConcreteBuilder装配;
  • Director(指挥者):定义一个construct()方法,复杂组件装配的顺序,返回构造好的对象,一般该类与客户端进行交互;内部维护一个Builder类;
  • 复杂对象:包含多个属性的对象;

(3)实现

@Data
public class Product {//产品类
    private String A;
    private String B;
}
public abstract class Builder {//建造者抽象类
    protected Product product=new Product();

    public abstract void buildPathA(String value);
    public abstract void buildPathB(String value);

    public Product getProduct(){
        return this.product;
    }
}
public class ConcreteBuilder extends Builder{//具体建造类
    @Override
    public void buildPathA(String value) {
        product.setA(value);
    }

    @Override
    public void buildPathB(String value) {
        product.setB(value);
    }
}
public class Director {//指挥者类
    private Builder builder;

    public Director(Builder builder){
        this.builder=builder;
    }

    public Product construct(String A,String B){
        builder.buildPathA(A);
        builder.buildPathB(B);
        return builder.getProduct();
    }
}
public class Main {
    public static void main(String[] args) {
        Builder builder=new ConcreteBuilder();
        Product product=new Director(builder).construct("属性A","属性B");
        System.out.println(product.getA());
        System.out.println(product.getB());
    }
}

(4)总结

优点:

  • 在建造者模式中,客户端不必直到内部如何构建,将产品本身与产品构建之间解耦,使得相同的构建过程可以构建不同的产品;
  • 每一个构建者相对独立,客户端可以很方便的添加新的构造者,同时增加新的构造者,不用修改原有的代码符合开闭原则;

缺点:

  • 产品之间相差过大,各个组成部分由较大差异,不适合使用该模式;
  • 产品的组件变化复杂,需要定义过多的构造类来实现这种变化,导致系统过于庞大;

使用场景:

  • 需要生成复杂对象,这些对象通常包含多个属性;
  • 对象之间的属性相互依赖,且由一定的顺序性;
  • 隔离复杂对象的创建和使用,使得相同的创建过程可以构建出不同的对象;

6、组合模式

(1)概述

  • 组合多个对象成为树形结构,对于叶子对象和容器对象的操作都具有一致性;
  • 当调用容器对象的某一个方法时,将会遍历整个树,寻找包含这个方法的成员变量,使用递归对整个树结构进行调用;
  • 叶子对象:没有字节点;
  • 容器对象:包含多个叶子对象和多个容器对象;

(2)角色

  • Component(抽象构件):为叶子构件和容器构件声明了接口,定义了其子类共有的行为方法;
  • Leaf(叶子构件):实现了Component接口中的行为方法,没有子节点;
  • Composite(容器构件):该节点有子节点,子节点可以是容器节点,也可以是叶子节点。有一个列表属性,用于存储子节点,实现了Component接口定义的行为方法,该方法可以递归调用子节点的业务方法;同时包含管理子构建的方法;

(3)实现

public abstract class Component {//抽象组件
    public abstract void add(Component component);//添加构建
    public abstract void remove(Component component);//删除构建
    public abstract List<Component> getChild();//获取子类
    public abstract void print();//输出文件
}
public class OssLeaf extends Component{//叶子组件
    private String name;

    public OssLeaf(String name){
        this.name=name;
    }

    @Override
    public void add(Component component) {
        System.out.println("异常处理");
    }

    @Override
    public void remove(Component component) {
        System.out.println("异常处理");
    }

    @Override
    public List<Component> getChild() {
        return null;
    }

    @Override
    public void print() {
        System.out.println("输出"+name+"文件");
    }
}
public class TxtLeaf extends Component{//叶子组件

    private String name;

    public TxtLeaf(String name){
        this.name=name;
    }

    @Override
    public void add(Component component) {
        System.out.println("异常处理");
    }

    @Override
    public void remove(Component component) {
        System.out.println("异常处理");
    }

    @Override
    public List<Component> getChild() {
        return null;
    }

    @Override
    public void print() {
        System.out.println("输出"+name+"文件类型");
    }
}
public class Composite extends Component{//容器组件
	//记录该组件的子组件(叶子组件、容器组件)
    private List<Component> componentList=new ArrayList<>();
    private String name;

    public Composite(String name){
        this.name=name;
    }

    @Override
    public void add(Component component) {
        componentList.add(component);
    }

    @Override
    public void remove(Component component) {
        componentList.remove(component);
    }

    @Override
    public List<Component> getChild() {
        return componentList;
    }

    @Override
    public void print() {
        System.out.println("输出"+name+"类型的文件,输出如下:");
        //调用子类的方法
        for (Component component : componentList) {
            component.print();
        }
    }
}
public class Main {//测试方法
    public static void main(String[] args) {
        OssLeaf ossLeaf1=new OssLeaf("图片");
        OssLeaf ossLeaf2=new OssLeaf("视频");

        TxtLeaf txtLeaf=new TxtLeaf("txt");
        TxtLeaf txtLeaf1=new TxtLeaf("docx");
        TxtLeaf txtLeaf2=new TxtLeaf("pptx");

        Composite composite1=new Composite("oss类型文件");
        composite1.add(ossLeaf1);
        composite1.add(ossLeaf2);
        composite1.print();

        Composite composite2=new Composite("文本类型文件");
        composite2.add(txtLeaf);
        composite2.add(txtLeaf1);
        composite2.add(txtLeaf2);
        composite2.print();

    }
}

(4)总结

优点:

  • 在新增新的叶子组件或容器组件时,无需修改原有代码,符合开闭原则;
  • 忽略客户端层次差异,方便对整个层次进行控制;

缺点:新增新的组件时,难以对组件的类型进行控制;

使用场景:

  • 需要处理一个树型结构;
  • 系统中可以分离出叶子组件和容器组件,类型不固定,需要增加一些新的类型;
  • 整体和部分具有层次结构,需要处理忽略他们的层次差,使用客户端一致调用这些业务方法;

7、观察者模式

(1)概述

  • 定义一种一堆多的关系,使得每当一个对象发生改变时,会通知其关联对象并自动更新;
  • 发生改变的对象为观察目标,而被通知的对象为观察者,这些观察者之间没有任何联系;

(2)角色

  • Subject(目标):被观察的对象,在目标中定义了一个观察者对象集合,提供删除,添加观察者的方法,同时定义了通知方法notify,可以是接口,抽象类或具体类;
  • ConcreteSubject(具体目标):Subject的子类,他包含发生改变的数据,当该数据发生改变时,会通知集合中的观察者,同时还实现目标类中的抽象业务方法;(无需扩展目标类,该类可以省略)
  • Observer(抽象观察者):观察者对改变做出响应,一般为接口,声明update方法;
  • ConcreteObserver(具体观察者):实现抽象观察者中的update方法,同时维护一个ConcreteSubject对象的应用,存储具体观察者有关状态,该状态需要与目标对象状态一致;

(3)实现

public abstract class Subject {//抽象目标
    public List<Observer> observerList=new ArrayList<>();//观察者集合

    public void add(Observer observer){//添加观察者
        observerList.add(observer);
    }

    public void delete(Observer observer){//删除观察者
        observerList.remove(observer);
    }

    public abstract void notifyObserver(String name);

}
public class ConcreteSubject extends Subject{//具体目标类
    @Override
    public void notifyObserver(String name) {
        //通知每一个观察者处理error
        for (Observer observer : observerList) {
            if (!((ConcreteObserver) observer).getName().equals(name)){
                observer.dealError();
            }
        }
    }
}
public interface Observer {//抽象观察者
    public void dealError();//在发生error时触发

    public void error(Subject subject);
}
public class ConcreteObserver implements Observer{//具体观察者
    private String name;

    public ConcreteObserver(String name){
        this.name=name;
    }

    public String getName(){
        return this.name;
    }

    //处理错误
    @Override
    public void dealError() {
        System.out.println(name+"来处理error了");
    }

    //发生错误
    @Override
    public void error(Subject subject) {
        System.out.println(name+"发生error,都来处理error");
        subject.notifyObserver(name);
    }
}
public class Main {
    public static void main(String[] args) {
        Subject subject=new ConcreteSubject();
        Observer observer1=new ConcreteObserver("A");
        Observer observer2=new ConcreteObserver("B");
        Observer observer3=new ConcreteObserver("C");
        subject.add(observer1);
        subject.add(observer2);
        subject.add(observer3);

        observer1.error(subject);
    }
}

(4)总结

优点:

  • 观察者适合广播通信,目标对象发生改变时,会通知所有订阅目标的观察者;
  • 添加具体观察者,无需修改原有代码,每一个观察者之间无任何联系,符合开闭原则;

缺点:

  • 目标类如果有过多的观察者,通知时会耗费大量时间;
  • 观察者和目标之间存在循环依赖,通知时,会导致死循环;
  • 观察者无法直到观察对象是如何变化的,只能直到该对象发生了变化;

使用场景:

  • 一个对象发生改变会影响多个对象,而这些对象之间相互无任何联系;
  • 链式触发,如A影响B,B影响C,。。。;

8、责任链模式

(1)概述

避免请求发送者和接收者耦合在一起,让多个对象都可以接收请求,将这些对象合成一条链,并且沿着这条链传递请求,直到有对象处理该请求为止;

(2)角色

  • Handler(抽象处理者):定义了一个处理请求的接口,不同的处理者对每一个请求的处理方式不同,因此定义抽象处理者。每一个处理者的下一个还是处理者,在抽象类中定义一个处理者对象,用于对下一个处理者的调用;
  • ConcreteHandler(具体处理者):抽象处理者的实现类,实现具体的请求处理方法,处理请求之前需要先判断是否有权限处理,有则处理,否则将请求转发给下一个处理者;

(3)实现

@Data
public abstract class Handler {
    protected Handler handler;//下一个处理者
    protected String name;//姓名

    public Handler(String name){
        this.name=name;
    }

    //处理请求逻辑方法
    public abstract void processorHandler(int money);
}
public class ConcreteHandlerA extends Handler{

    public ConcreteHandlerA(String name){
        super(name);
    }

    @Override//可以审批5000元以下
    public void processorHandler(int money) {
        if (money<=5000){
            System.out.println(name+"进行审批,审批通过");
        }else {
            System.out.println(name+"无法审批金额,流转下一个审批者");
            handler.processorHandler(money);
        }
    }
}
public class ConcreteHandlerB extends Handler{

    public ConcreteHandlerB(String name){
        super(name);
    }

    @Override//可以审批5000-20000
    public void processorHandler(int money) {
        if (money>5000&&money<=20000){
            System.out.println(name+"进行审批,审批通过");
        }else {
            System.out.println(name+"无法审批金额,流转下一个审批者");
            handler.processorHandler(money);
        }
    }
}
public class ConcreteHandlerC extends Handler{

    public ConcreteHandlerC(String name){
        super(name);
    }

    @Override//可以审批20000以上
    public void processorHandler(int money) {
        if (money>20000){
            System.out.println(name+"进行审批,审批通过");
        }else {
            System.out.println(name+"无法审批金额,流转下一个审批者");
            handler.processorHandler(money);
        }
    }
}
public class Main {
    public static void main(String[] args) {
        Handler handlerA=new ConcreteHandlerA("主管");
        Handler handlerB=new ConcreteHandlerB("经理");
        Handler handlerC=new ConcreteHandlerC("董事长");
        //设置下一个处理者
        handlerA.setHandler(handlerB);
        handlerB.setHandler(handlerC);
        handlerA.processorHandler(30000);
    }
}

(4)总结

优点:

  • 发送者和接收者都没有对方的信息,只知道请求会被处理,降低系统耦合度;
  • 职责链的处理更加灵活,可以动态增加和删除处理者,来改变处理一个请求的职责;
  • 增加一个新的请求者无需修改原有代码,只需添加新连接即可,符合开闭原则;

缺点:

  • 请求没有明确接收者,可能导致请求走完职责链也并未被处理;
  • 请求处理需要多个对象进行处理,系统性能将受一定的影响;
  • 创建的连接不当,可能会造成系统死循环;

使用场景:

  • 多个对象处理一个请求,请求需要等到运行时才能确定哪一个处理者处理;
  • 不明确处理者对象,向多个对象提交一个请求;
  • 指定一组对象进行处理,客户端可以动态添加处理对象,并且可以改变顺序;

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

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

相关文章

分享2个u盘还原方法,轻松恢复u盘数据!

U盘&#xff0c;作为便捷的存储设备&#xff0c;经常用于传输和存储重要文件。然而&#xff0c;由于误操作、病毒感染或其他原因&#xff0c;U盘上的数据可能会丢失。在这种情况下&#xff0c;进行u盘还原成为救回丢失数据的关键一步。 本文将解释U盘还原的意义&#xff0c;并…

利用数据透视表统计出现的次数

一、统计出现的次数 注意&#xff1a;字段是直接使用左键拖动到求和栏中即可。 二、表内数据求和 三、按时间统计&#xff08;参考该文&#xff09;

RT_Thread内核机制学习(二)

对于RTT来说&#xff0c;每个线程创建时都自带一个定时器 rt_err_t rt_thread_sleep(rt_tick_t tick) {register rt_base_t temp;struct rt_thread *thread;/* set to current thread */thread rt_thread_self();RT_ASSERT(thread ! RT_NULL);RT_ASSERT(rt_object_get_type(…

Protobuf高性能接口ZeroCopyStream

Protobuf ZeroCopyStream 1.ZeroCopyStream protobuf在io接口上有一个叫做ZeroCopyStream&#xff0c;对于IO的接口设计&#xff0c;pb提供了相关序列化与反序列化接口&#xff0c;如&#xff1a; // Read a protocol buffer from the given zero-copy input stream. If // su…

Bigemap在公路勘察设计行业中如何应用呢?

选择Bigemap的原因&#xff1a; Google 已经停止使用&#xff0c;天地图清晰度偏低&#xff0c;bigmap可以提供多种不同源的影像、矢量数据。奥维&#xff0c;有接触&#xff0c;做了比选&#xff0c;后来从技术本身去考虑这个问题&#xff0c;影像、矢量数据下载方便&#xf…

命令行环境题目

在后台产生一个ID 不会输出任何东西

Golang Gorm 一对多的添加

一对多的添加有两种情况&#xff1a; 一种是添加用户的时候同时创建文章其次是创建文章关联已经存在的用户。 package mainimport ("gorm.io/driver/mysql""gorm.io/gorm" )// User 用户表 一个用户拥有多篇文章 type User struct {ID int64Name …

强强联袂,产教融合丨知了汇智与成都世纪超体达成战略合作

为了共培数字营销人才&#xff0c;实现产业、教育双向赋能&#xff0c;为地方乃至全国电商发展注入源源不断的行业性人才&#xff0c;8月24日&#xff0c;成都知了汇智科技有限公司&#xff08;以下简称“知了汇智”&#xff09;与成都世纪超体科技有限公司&#xff08;以下简称…

科技资讯|苹果发布新专利:可在车内定位苹果的智能设备

根据美国商标和专利局近期公示的清单&#xff0c;苹果公司获得了一项名为《车内定位移动设备的系统和方式》专利&#xff0c;概述了在车内狭窄空间内如何定位 iPhone 等移动设备。 Find My 服务现阶段没有使用 UWB 来追踪 iPhone 或者 iPad&#xff0c;而是依赖 GPS 等相关辅…

iTubeGo for Mac视频下载器

iTubeGo YouTube Downloader是一款功能强大的YouTube视频下载工具&#xff0c; 它具有以下特色&#xff1a; 多种格式支持&#xff1a;iTubeGo YouTube Downloader可以将YouTube视频下载为多种常见的视频和音频格式&#xff0c;包括MP4、MP3、AVI、FLV、MOV、WMV等&#xff0c…

RFID服装管理系统:点亮时尚世界的新星

今天我们要聊聊一个真正酷炫的系统——RFID服装管理系统。別担心&#xff0c;我会用最地道的方式跟你聊&#xff0c;咱们来解开这神秘的时尚密码吧&#xff01; 首先&#xff0c;先別怕&#xff0c;RFID其实是射频识别技术的缩写。别觉得高大上&#xff0c;其实就是让你的服装…

docker容器查看所有没使用的镜像,并删除

文章目录 场景1. 删除不用的容器删除无效容器2. 删除不用的镜像 场景 最近工作中遇到服务器磁盘紧张的情况&#xff0c;想到docker镜像和容器可以删除些不用的&#xff0c;省出来一些空间。具体操作如下: 1. 删除不用的容器 首先执行命令 docker ps -a 查看容器列表&#xff…

Maven 基础之安装和命令行使用

Maven 的安装和命令行使用 1. 下载安装 下载解压 maven 压缩包&#xff08;http://maven.apache.org/&#xff09; 配置环境变量 前提&#xff1a;需要安装 java 。 在命令行执行如下命令&#xff1a; mvn --version如出现类似如下结果&#xff0c;则证明 maven 安装正确…

ZeroMQ入门

官网: ZeroMQ 简介 ZeroMQ是一个库&#xff0c;不是消息队列也不是消息中间件&#xff0c;介于应用层和传输层之间&#xff08;按照TCP/IP划分&#xff09;。 传统的Socket通信模式需要创建连接&#xff0c;销毁连接&#xff0c;选择协议等一些列操作。而ZeroMQ是在Socket封…

①matlab的命令掌握

目录 输入命令 命名变量 保存和加载变量 使用内置的函数和常量 输入命令 1.您可以通过在命令行窗口中 MATLAB 提示符 (>>) 后输入命令 任务 使用命令 3*5 将数值 3 和 5 相乘。 答案 3*5 2.除非另有指定&#xff0c;否则 MATLAB 会将计算结果存储在一个名为 ans…

No119.精选前端面试题,享受每天的挑战和学习

文章目录 实现栈&#xff0c;有入栈出栈的方法&#xff0c;以及length属性如何封装组件单页应用怎么跨页面传参权限怎么设计的map和forEach对于对象类型会不会改变 实现栈&#xff0c;有入栈出栈的方法&#xff0c;以及length属性 可以通过 JavaScript 的数组来实现一个栈结构…

倒数 2 周|期待 2023 Google开发者大会

9 月 6-7 日&#xff0c;中国上海 前沿科技&#xff0c;新知同享 趣味体验&#xff0c;灵感齐聚 技术生态&#xff0c;多元共进 关注官网最新信息&#xff0c;敬请期待大会开幕 2023 Google 开发者大会官网 相信你一定记得&#xff0c;在今年 5 月的 Google I/O 大会上&am…

考察交流 | 九江市浔阳区委常委、副区长雷霆钧一行考察中创算力

考察交流 8月25日&#xff0c;九江市浔阳区委常委、副区长雷霆钧来访中创算力开展招商考察&#xff0c;中创董事长许伟威热情接待了调研领导一行。浔阳区数字经济发展中心主任曹超成、九江电信浔阳分局局长黄健、九江新联智创董事长刘诚志、德国石荷州中资企业协会副会长陈虹瑾…

SAP从放弃到入门系列之abapGit安装

文章目录 一、概括二、系统环境三、安装独立版本四、安装开发者版本4.1、在线安装&#xff08;推荐&#xff09;4.2、离线安装 前段时间看了汪子熙老师关于abap2UI5的文章&#xff0c;感觉很有意思,来了解一下。abapGit 安装的文章已经有很多了&#xff0c;但是为了在系统里使用…

redis windows 版本安装

1. 下载windows安装包并解压 如果是Linux版本可以直接到官网下载&#xff0c;自3.x起官网和微软网站就没有redis安装包更新了&#xff0c;好在github有开发者在编译发布更新&#xff08;目前最新有5.0.9版本可下&#xff09;&#xff0c;地址&#xff1a;redis windows 5版本下…