23种设计模式之结构型模式篇

二、结构型模式

这类模式主要处理类或对象的组合,涉及如何组合类和对象以获得更大的结构。

包括:
  • 适配器模式(Adapter)
  • 装饰器模式(Decorator)
  • 代理模式(Proxy)
  • 外观模式(Facade)
  • 桥接模式(Bridge)
  • 组合模式(Composite)
  • 享元模式(Flyweight)
1、代理模式(Proxy)
1.1.代码实现
//操作步骤一:主题接口
public interface Subject {
    void request();
}

//操作步骤二:一个实现Subject接口的类SubjectImpl
public class SubjectImpl implements Subject {

    @Override
    public void request() {
        System.out.println("真实主题的请求");
    }
}


//操作步骤三:一个实现Subject接口的代理类SubjectProxy
public class SubjectProxy implements Subject {

    SubjectImpl subjectImpl;

    @Override
    public void request() {

        if(subjectImpl==null){
            subjectImpl=new SubjectImpl();
        }
        preRequest();       //1.预处理
        subjectImpl.request();      //2.真实主题处理
        postRequest();      //2.后处理
    }

    /**
     * 代理类的预处理
     * */
    private void preRequest() {
        System.out.println("代理类的预处理");
    }

    /**
     *代理类的后处理
     * */
    private void postRequest() {
        System.out.println("代理类的后处理");
    }

}

//代码测试
public class ProxyTest {
    /**
     * 代理模式(AOP):
     * 代理模式是一种设计模式,它通过创建一个代理对象来控制对原始对象的访问。以下是一个简单的Java代理模式示例:
     * 1.创建一个接口Subject:
     * 2.创建一个实现Subject接口的类SubjectImpl:
     * 3.创建一个实现Subject接口的代理类SubjectProxy
     * 4.最后,我们在main方法中使用代理类Proxy来调用真实主题的方法:
     */
    public static void main(String[] args) {
        Subject proxy = new SubjectProxy();
        proxy.request();

    }
}
1.2.概念总结
1.2.1.代理模式的作用:
  1. **控制访问:**代理模式可以控制对原始对象的访问,例如可以在访问对象之前或之后执行一些额外的操作,如权限检查、日志记录等。

  2. **扩展功能:**代理模式可以在不修改原始对象的基础上,通过代理类来扩展对象的功能。这意味着可以在不影响原有代码的情况下,为对象添加新的行为或特性。

  3. **智能化处理:**代理能够实现智能化处理,比如动态代理可以在运行时动态地生成代理对象,这为处理一些需要在运行时才能确定具体行为的情况提供了便利。

  4. **职责清晰:**在代理模式中,代理对象和真实对象的职责是分开的,这样可以使得代码的结构更加清晰,各个部分的职责更加明确。

  5. **高扩展性:**由于代理模式基于接口或抽象类进行编程,只要实现了相应的接口,就可以被代理,这使得系统具有很高的扩展性。

1.2.2.代理模式常用于以下场景:
  1. **远程代理:**为远程对象提供局部代表,以减少网络通信的开销。

  2. **虚拟代理:**根据需要创建开销大的对象,通过代理来实现对象的延迟加载。

  3. **安全代理:**用来控制不同权限的对象对原对象的访问。

  4. **智能指引:**当对象无法自行决定如何处理时,由代理来决定。

  5. **懒加载代理:**在需要时才加载实际对象,以提高性能。

总的来说,代理模式是一种非常实用的设计模式,它通过引入一个中介层,即代理对象,来控制和增强对真实对象的访问。这种模式在软件设计中广泛应用,尤其是在需要对对象的访问进行控制或扩展其功能时。

2、适配器模式(Adapter)
2.1.代码实现
//操作步骤一:目标接口
public interface Target {
    void request();
}

//操作步骤二:适配器类
public class Adapter implements Target {

    private Adaptee adaptee;

    public Adapter(Adaptee adaptee) {
        this.adaptee = adaptee;
    }

    @Override
    public void request() {
        adaptee.specificRequest();
    }
}

//操作步骤三:适配者类
public class Adaptee {
    public void specificRequest() {
        System.out.println("Adaptee's specificRequest");
    }

}

//代码测试
public class AdapterTest {
    public static void main(String[] args) {
        //1.适配者类
        Adaptee adaptee = new Adaptee();

        //2.适配器类
        Target target = new Adapter(adaptee);

        //3.目标接口
        target.request(); // 输出:Adaptee's specificRequest
    }
}
2.2.概念总结

适配器模式是一种结构型设计模式,它通过将一个接口转换成客户期望的另一个接口,使得原本不兼容的两个类能够协同工作。

2.2.1.适配器模式的核心在于解决两个不同接口之间的兼容性问题。这种模式通常涉及到以下角色:
  • **目标(Target)接口:**这是客户端所期待的接口,定义了客户端希望使用的方法和功能。
  • **适配者(Adaptee)类:**这是一个现有的类,其接口与客户期望的目标接口不兼容。
  • **适配器(Adapter)类:**这个类实现了目标接口,并且持有一个对适配者类的引用。它通过调用适配者的方法来实现目标接口的功能。

在实际应用中,适配器模式可以有几种不同的实现方式,包括类适配器、对象适配器和接口适配器。这些实现方式各有特点,但核心目的相同,即提供一种机制来协调不兼容的接口之间的差异。

2.2.2.适配器模式的优点包括:
  • **复用性:**它可以让现有的类(适配者)与新的接口(目标)协同工作,从而重用已有的代码。
  • **灵活性:**可以在不修改原有代码的基础上增加新功能。
  • **解耦:**由于适配器作为中间层,它减少了系统各部分之间的直接依赖。
2.2.3.适配器模式缺点:
  • **系统复杂性:**引入适配器可能会增加系统的复杂性,因为需要额外的类来处理接口转换。
  • **性能开销:**调用适配器可能会引入一定的性能开销,特别是在频繁调用的场景下。

总的来说,适配器模式是一种非常有用的设计模式,它通过提供一个中间层来解决不同接口之间的兼容性问题,从而使得系统更加灵活和可扩展。

3、装饰者模式(Decorate)
3.1.代码实现
//操作步骤一:定义组件接口
public interface Component {
    void operation();
}

//操作步骤二:实现组件接口的具体类
public class ConcreteComponent implements Component{
    @Override
    public void operation() {
        System.out.println("执行原始操作");
    }
}

//操作步骤三:定义装饰者抽象类,继承自组件接口
public abstract class Decorator implements Component{
    protected Component component;

    public Decorator(Component component) {
        this.component = component;
    }

    public void operation() {
        component.operation();
    }
}

//操作步骤四:实现具体装饰者类
public class ConcreteDecoratorA extends Decorator{

    public ConcreteDecoratorA(Component component) {
        super(component);
    }

    public void operation() {
        System.out.println("执行装饰者A的操作");
        super.operation();
    }
}

//操作步骤四:实现具体装饰者类
public class ConcreteDecoratorB extends Decorator {
    public ConcreteDecoratorB(Component component) {
        super(component);
    }

    public void operation() {
        System.out.println("执行装饰者B的操作");
        super.operation();
    }
}

//测试代码
public class DecoratorTest {
    public static void main(String[] args) {
        //1.创建原始对象
        Component component = new ConcreteComponent();

        //2.创建装饰者对象,并传入原始对象
        Decorator decoratorA = new ConcreteDecoratorA(component);
        Decorator decoratorB = new ConcreteDecoratorB(decoratorA);

        //3.执行装饰后的操作
        decoratorB.operation();
    }
}
3.2.概念总结

装饰者模式是一种结构型设计模式,它允许在不改变对象原有结构的情况下,动态地添加功能和责任

装饰者模式的核心思想是使用组合而非继承来扩展对象的功能。这种模式通过创建一个包装对象,即“装饰者”,来包裹原始对象,从而在不修改原始对象的代码的情况下,为其添加新的行为或职责。这样做的好处是可以实现高度的灵活性和可扩展性,同时遵循了开闭原则(对扩展开放,对修改关闭)。

在Java中,装饰者模式通常使用接口或抽象类来实现,确保所有组件(包括原始对象和装饰者)都实现相同的接口或继承自相同的抽象类。这样,装饰者类可以反映出被装饰组件的类型,使得客户端可以统一处理原始对象和装饰后的对象。

3.2.1装饰者模式的一些关键特点:
  1. 透明性:装饰者模式应该对客户端透明,即客户端无需区分原始对象和装饰后的对象,它们应当具有相同的接口或类型。
  2. 动态性:装饰者可以在运行时动态地添加到对象上,这意味着可以根据需要随时增加或减少对象的职责。
  3. 灵活性:与继承相比,装饰者模式提供了更大的灵活性,因为它允许在不改变现有类的基础上添加新功能。
  4. 替代继承:当不适合使用子类进行扩展时,装饰者模式可以作为一种替代方法,以避免类层次过于复杂。

总的来说,装饰者模式适用于那些需要为对象动态添加功能的场景,尤其是在不希望通过继承来扩展类的情况下。

4、外观模式(Facade)
4.1.代码实现
//操作步骤一:子系统A
public class SubsystemA {
    public void operationA() {
        System.out.println("Subsystem A operation");
    }
}

//操作步骤一:子系统B
public class SubsystemB {
    public void operationB() {
        System.out.println("Subsystem B operation");
    }
}

//操作步骤一:子系统C
public class SubsystemC {
    public void operationC() {
        System.out.println("Subsystem C operation");
    }
}

//操作步骤二:外观类
public class Facade {
    private SubsystemA subsystemA;

    private SubsystemB subsystemB;

    private SubsystemC subsystemC;

    public Facade() {
        subsystemA = new SubsystemA();
        subsystemB = new SubsystemB();
        subsystemC = new SubsystemC();
    }

    public void operation() {
        subsystemA.operationA();
        subsystemB.operationB();
        subsystemC.operationC();
    }
}

//测试代码
public class FacadeTest {
    /**
     * 1.定义了三个子系统SubsystemA、SubsystemB和SubsystemC,它们分别实现了各自的操作。
     * 2.然后,我们创建了一个外观类Facade,它封装了对这三个子系统的访问,
     		并提供了一个统一的接口operation()来执行这些操作。
     * 3.最后,在客户端代码中,我们通过创建Facade对象并调用其operation()方法来简化对子系统的访问。
     *
     * 这样,客户端只需要与外观类交互,而不需要直接与子系统进行交互,从而降低了系统的复杂性。
     * 同时,如果需要添加新的子系统或修改现有子系统的操作,只需修改外观类即可,而无需修改客户端代码。
     * */
    public static void main(String[] args) {
        Facade facade = new Facade();
        facade.operation();
    }
}
4.2.概念总结

外观模式是一种结构型设计模式,用于简化多个子系统之间的复杂交互,并为客户端提供一个统一的接口来访问这些子系统。

外观模式的核心思想是创建一个高层接口,这个接口可以隐藏系统的内部工作细节,使得子系统更容易被使用。通过引入一个外观类,它为复杂的子系统调用提供了一个统一的入口,从而降低了子系统与客户端之间的耦合度。

4.2.1.外观模式的优点:
  • 降低复杂性:通过提供一个简单的接口,外观模式帮助客户端屏蔽了子系统的复杂性。
  • 松耦合:客户端不直接与子系统交互,从而减少了它们之间的依赖关系。
  • 易于扩展:新的子系统可以很容易地添加到外观之后,而不需要修改现有的客户端代码。

然而,外观模式也有一些缺点,比如可能会增加系统的抽象层次,有时候可能会导致不必要的间接层。

4.2.2.外观模式适用于以下情况:
  • 当需要为复杂的子系统提供一个简单接口时。
  • 当客户端不应该直接访问子系统内部的类时。
  • 当需要简化并统一多个子系统的操作时。

综上所述,外观模式是一种有效的设计模式,用于简化复杂系统的接口并提供一个统一的访问点,从而提高系统的可维护性和可扩展性。

5、桥接模式(Bridge)
5.1.代码实现
//操作步骤一:接口:绘图API
public interface DrawAPI {
    void drawCircle(int radius, int x, int y);

    void drawSquare(int side, int x, int y);
}
//操作步骤二:抽象类:形状
public abstract class Shape {
    protected DrawAPI drawAPI;

    protected Shape(DrawAPI drawAPI) {
        this.drawAPI = drawAPI;
    }

    public abstract void draw();
}
//操作步骤三:实现类:正方形
public class Square extends Shape {
    private int x, y, side;

    public Square(int x, int y, int side, DrawAPI drawAPI) {
        super(drawAPI);
        this.x = x;
        this.y = y;
        this.side = side;
    }

    @Override
    public void draw() {
        drawAPI.drawSquare(side, x, y);
    }
}
//操作步骤四:实现类:圆形
public class Circle extends Shape {
    private int x, y, radius;

    public Circle(int x, int y, int radius, DrawAPI drawAPI) {
        super(drawAPI);
        this.x = x;
        this.y = y;
        this.radius = radius;
    }

    @Override
    public void draw() {
        drawAPI.drawCircle(radius, x, y);
    }
}

//操作步骤五:实现类:Windows API
public class WindowsDrawAPI implements DrawAPI {
    @Override
    public void drawCircle(int radius, int x, int y) {
        System.out.println("Drawing Circle[ color: red, radius: " + radius + ", x: " + x + ", y: " + y + "]");
    }

    @Override
    public void drawSquare(int side, int x, int y) {
        System.out.println("Drawing Square[ color: blue, side: " + side + ", x: " + x + ", y: " + y + "]");
    }
}
//操作步骤六:实现类:Mac OS X API
public class MacOSXDrawAPI implements DrawAPI {
    @Override
    public void drawCircle(int radius, int x, int y) {
        System.out.println("Drawing Circle[ color: green, radius: " + radius + ", x: " + x + ", y: " + y + "]");
    }

    @Override
    public void drawSquare(int side, int x, int y) {
        System.out.println("Drawing Square[ color: yellow, side: " + side + ", x: " + x + ", y: " + y + "]");
    }
}

//测试代码
public class BridgeTest {
    public static void main(String[] args) {
        Shape circle = new Circle(100, 100, 10, new WindowsDrawAPI());

        Shape square = new Square(100, 100, 20, new MacOSXDrawAPI());

        circle.draw();
        square.draw();
    }
}
5.2.概念总结

桥接模式是一种设计模式,旨在将抽象与实现分离开来,使得两者可以独立变化。这种模式属于对象结构型模式。具体来说,桥接模式有以下要点:

  • 分离抽象和实现:它允许开发者将一个抽象类的抽象性与其具体实现分开处理。这样做的目的是为了避免类层次爆炸,当一个类无法同时满足多个维度的分类时尤其有用。
  • 增加灵活性:通过桥接模式,可以在两个或多个独立变化的维度之间增加灵活性。例如,在图形应用程序中,形状(如圆形、正方形)和颜色(如红、蓝)可以独立变化,使用桥接模式可以将它们的变化解耦。
  • 减少子类的生成:在不使用桥接模式的情况下,可能需要为每种可能的组合创建子类,这将导致类的数量急剧增加。桥接模式通过提供一个桥梁结构来连接不同的部分,从而避免了大量子类的产生。
  • 适用于特定场景:当系统需要跨多个独立变化的维度进行扩展时,或者当一个类存在多个维度的分类且这些分类应该被独立地变化和扩展时,桥接模式是一个合适的选择。
  • 示例应用:桥接模式可以应用于多种业务场景,如软件框架设计、工具库开发等。以星巴克订单系统为例,可以使用桥接模式将订单的创建过程与支付方式分离,使得新增支付方式或订单类型时不需要修改现有代码。

总的来说,桥接模式是一种强大的设计工具,它通过分离抽象与实现,提供了一种优雅的方式来管理类之间的复杂关系。在实际应用中,正确使用桥接模式可以极大地提高系统的灵活性和可维护性。

6、组合模式(Composite)
6.1.代码实现
//操作步骤一:组件接口
public interface Component {
     void operation();
}
//操作步骤二:叶子节点
public class Leaf implements Component {

    private String name;

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

    @Override
    public void operation() {
        System.out.println("Leaf " + name + " operation.");
    }
}

//操作步骤三:组合对象
public class Composite implements Component {

    private String name;

    private List<Component> children = new ArrayList<>();

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

    public void add(Component component) {
        children.add(component);
    }

    public void remove(Component component) {
        children.remove(component);
    }

    @Override
    public void operation() {
        System.out.println("Composite " + name + " operation.");
        for (Component component : children) {
            component.operation();
        }
    }
}

//测试代码
public class CompositeTest {
    /**
     * Component是一个接口,Leaf是组成该树的叶子节点,而Composite是组合节点,
     		它可以包含其他的叶子节点或者组合节点。
     * main方法中创建了一个组合结构的树,并展示了如何执行根节点的操作,它会递归地调用所有子节点的操作。
     * */
    public static void main(String[] args) {

        Composite root = new Composite("Root");
        root.add(new Leaf("Leaf A"));
        root.add(new Leaf("Leaf B"));

        Composite branch = new Composite("Branch");
        branch.add(new Leaf("Leaf C"));
        branch.add(new Leaf("Leaf D"));

        root.add(branch);
        root.operation();
    }
}
6.2.概念总结

组合模式是一种结构型设计模式,它允许将对象组合成树形结构以表现“整体/部分”的层次结构。组合模式使得客户端对单个对象和组合对象的使用具有一致性。

6.2.1组合模式通常包括以下几个角色:
  1. 抽象组件(Component):定义统一的接口或抽象类,规定了叶子节点对象和容器节点对象的共有操作。在抽象组件中通常会声明一些基础的操作,如operation(),以及用于管理子组件的接口方法,例如add()remove()等。
  2. 叶子节点(Leaf):表示组合中的最小构建块,没有子节点。它实现了抽象组件接口的行为,但对于添加或删除子项的操作不进行实际操作,因为叶子节点下不能再包含其他节点。
  3. 组合对象(Composite):是一个容器节点,可以包含叶子节点或其他组合对象作为其子节点。它同样实现抽象组件的接口,并重写操作方法来对子组件进行管理。
6.2.2.组合模式适用情形:
  1. 当你希望客户端忽略组合与单个对象的不同,能够统一对待它们时。
  2. 当希望处理一个对象集合,并且这个集合可以递归地包含其他子集合或成员时。
  3. 当想表示对象的部分-整体层次结构时。

例如,在管理公司的组织架构时,可以使用组合模式来表示部门和员工的关系。部门可以作为组合对象,包含多个子部门或员工,而员工则是叶子节点。通过这种方式,可以轻松地对整个组织结构进行遍历、添加或移除部门和员工等操作。

综上所述,组合模式的优点在于能够简化客户端代码,因为客户端无需区分是处理单个对象还是组合对象;同时也使得在设计和实现树状结构时更加灵活和简单。不过,需要注意的是,在使用组合模式时,应确保组件的接口足够通用,以便适应各种类型的子组件。

7、享元模式(Flyweight)
7.1.代码实现
//操作步骤一:抽象享元类
public abstract class Flyweight {
    private String key;

    public Flyweight(String key) {
        this.key = key;
    }

    public abstract void operation();

    public String getKey() {
        return key;
    }
}

//操作步骤二:具体享元类A
public class ConcreteFlyweightA extends Flyweight {
    public ConcreteFlyweightA(String key) {
        super(key);
    }

    @Override
    public void operation() {
        System.out.println("ConcreteFlyweightA with key: " + getKey());
    }
}

//操作步骤二:具体享元类B
public class ConcreteFlyweightB extends Flyweight {
    public ConcreteFlyweightB(String key) {
        super(key);
    }

    @Override
    public void operation() {
        System.out.println("ConcreteFlyweightB with key: " + getKey());
    }
}

//操作步骤三:享元工厂类
public class FlyweightFactory {
    private Map<String, Flyweight> flyweights = new HashMap<>();

    public Flyweight getFlyweight(String key) {
        if (!flyweights.containsKey(key)) {
            if (key.equals("A")) {
                flyweights.put(key, new ConcreteFlyweightA(key));
            } else if (key.equals("B")) {
                flyweights.put(key, new ConcreteFlyweightB(key));
            }
        }
        return flyweights.get(key);
    }
}

//测试代码
public class FlyweightTest {
    /**
     * 1.Flyweight是抽象享元类,定义了一个operation()方法用于执行具体的操作。
     * 2.ConcreteFlyweightA和ConcreteFlyweightB是具体享元类,分别实现了Flyweight接口,
     		并重写了operation()方法。
     * 3.FlyweightFactory是享元工厂类,负责创建和管理享元对象。
     *
     * 在客户端代码中,通过调用FlyweightFactory的getFlyweight()方法来获取享元对象,并执行相应的操作。
     * 由于享元对象的共享特性,当请求相同的享元时,会返回已经存在的享元对象,从而节省内存开销。
     * */
    public static void main(String[] args) {
        FlyweightFactory factory = new FlyweightFactory();

        Flyweight flyweightA1 = factory.getFlyweight("A");
        Flyweight flyweightA2 = factory.getFlyweight("A");
        Flyweight flyweightB1 = factory.getFlyweight("B");

        flyweightA1.operation(); // 输出:ConcreteFlyweightA with key: A
        flyweightA2.operation(); // 输出:ConcreteFlyweightA with key: A
        flyweightB1.operation(); // 输出:ConcreteFlyweightB with key: B
    }
}

7.2.概念总结

享元模式是一种结构型设计模式,旨在减少对象的创建数量,以节省内存空间和提高程序性能

以下是关于享元模式的一些关键信息:

  1. 角色组成:它通常包括以下几个角色:

    • 享元工厂(Flyweight Factory):负责创建和管理享元对象,当客户端请求一个享元时,享元工厂会检查是否已经有现成的享元对象可以提供,如果没有,它会创建一个新的享元对象。
    • 抽象享元(Abstract Flyweight):定义一个接口,通过这个接口,享元工厂可以创建具体享元类的实例。
    • 具体享元(Concrete Flyweight):实现抽象享元接口的具体类,这些类的对象可以被共享使用。
  2. 与单例模式的区别:享元模式涉及多个对象,而单例模式确保一个类只有一个实例。享元模式的目的是节约内存,而单例模式则是为了控制资源的访问或确保某个类有且仅有一个实例。

  3. 应用场景:适用于系统中存在大量相似对象,而这些对象又可以通过共享某些相同数据来减少内存占用的情况。例如,文档编辑器中的字体、图像编辑软件中的图标等,都可以通过享元模式来实现高效的内存管理。

  4. 优势:享元模式通过共享已经存在的对象来大幅度减少需要创建的对象数量,避免了因大量相似对象的创建而导致的内存浪费,从而提高了系统资源的利用率。

综上所述,享元模式是一种优化内存使用的设计模式,适用于需要大量相似对象的场合,通过共享对象来减少内存开销,提升系统性能。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

1张图片+3090显卡微调Qwen-VL视觉语言大模型(仅做演示、效果还需加大数据量)

原项目地址&#xff1a;https://github.com/QwenLM/Qwen-VL/blob/master/README_CN.md 环境本地部署&#xff08;见之前博文&#xff09; 【本地部署 】23.08 阿里Qwen-VL&#xff1a;能对图片理解、定位物体、读取文字的视觉语言模型 (推理最低12G显存) 一、数据集格式说明 …

『视觉感官盛宴』3D线上商场全方位展示商品与互动购买体验

随着技术的进步和消费者需求的多样化&#xff0c;3D线上商场作为一种新兴的电子商务平台&#xff0c;正逐渐改变传统的在线购物模式。 一、商品展示革命 在3D线上商场中&#xff0c;商品展示不再局限于静态图片和文字描述。借助先进的3D建模技术&#xff0c;商家能够创建商…

从0到1带你玩转pandas

学习 pandas 的过程可以分为几个阶段&#xff0c;每个阶段都围绕着不同的核心技能和概念。下面是一个为初学者设计的学习大纲&#xff1a; 一. 基础介绍 学习如何安装和设置 pandas 以及了解它的基本概念是开始使用 pandas 进行数据分析的第一步。下面我将详细介绍这些步骤&am…

【MySQL】A01、性能优化-语句分析

1、数据库优化方向 A、SQL及索引优化 根据需求写出良好的SQL&#xff0c;并创建有效的索引&#xff0c;实现某一种需求可以多种写法&#xff0c;这时候我们就要选择一种效率最高的写法。这个时候就要了解sql优化 B、数据库表结构优化 根据数据库的范式&#xff0c;设计表结构&…

mac电脑搭建vue环境(上篇)

第一步&#xff1a;mac电脑要有homebrew&#xff0c;如何安装homebrew 点击下方 MAC安装homebrew-CSDN博客 第二步&#xff1a;homebrew安装node.js 第三步&#xff1a;安装npm 第四步&#xff1a;安装webpack 第五步&#xff1a;安装vue脚手架 第六步&#xff1a;可以在…

翻译《The Old New Thing》 - Some reasons not to do anything scary in your DllMain

Some reasons not to do anything scary in your DllMain - The Old New Thing (microsoft.com)https://devblogs.microsoft.com/oldnewthing/20040127-00/?p40873 Raymond Chen 2004年01月27日 简介 这篇文章讨论了为什么不应该在DLL的DllMain函数中执行复杂的操作 正文 众所…

Java中的重写

package day34; ​ public class Father {String name;int age;public void 输出(){System.out.println("father");} } ​ package day34; ​ public class Son extends Father{Overridepublic void 输出() {System.out.println("son");} } ​ package d…

C++:构造函数和析构函数

一、构造函数 1.1概念 构造函数是一个特殊的成员函数&#xff0c;名字与类相同&#xff0c;创建类类型对象时由编译器自动调用&#xff0c;保证每个数据成员都由一个合适的初始值。在对象的生命周期内只调用一次。 不使用构造函数 #include<iostream> using namespac…

美国站群服务器如何解决跨国运营中的网络延迟问题?

美国站群服务器如何解决跨国运营中的网络延迟问题? 在当今全球化的商业环境中&#xff0c;跨国企业面临的一个重要挑战是网络延迟问题。网络延迟不仅影响用户体验&#xff0c;还可能导致交易失败或数据传输错误&#xff0c;对企业造成不利影响。然而&#xff0c;利用美国站群…

982: 输出利用二叉树存储的普通树的度

解法&#xff1a; 由题意&#xff0c;根据二叉树求对应的合法普通树的度&#xff0c;度就是节点儿子数的最大值。 也就是左孩子&#xff0b;兄弟 在二叉树中就是某根节点的右孩子某根节点的右孩子的右孩子。。。 例AB#CD##E### 关于树概念不理解的可以看看981: 统计利用二叉…

【目标检测】YOLOv7 网络结构(与 YOLOv4,YOLOv5 对比)

YOLOv7 和 YOLOv4 Neck 与 Head 结构对比 其实 YOLOv7 的网络结构网上很多文章已经讲得很清除了&#xff0c;网络结构图也有非常多的版本可供选择&#xff0c;因为 YOLOv7 和 YOLOv4 是一个团队的作品&#xff0c;所以在网络结构方面&#xff0c; YOLOv7 和 YOLOv4 有很多相似…

解决配置Tomcat时,找不到war和war exploded问题

解决配置Tomcat时&#xff0c;找不到war和war exploded问题 文章目录 解决配置Tomcat时&#xff0c;找不到war和war exploded问题前言一、解决方法&#xff1a;1. war exploded2. war 总结 前言 提示&#xff1a;以下是本篇文章正文内容&#xff1a; 一、解决方法&#xff1a;…

mac电脑搭建vue项目(下篇)

第三步&#xff1a;安装npm &#xff08;1&#xff09;执行以下命令安装cnpm淘宝镜像 sudo npm install -g cnpm --registryhttps://registry.npmmirror.com &#xff08;2&#xff09;执行命令cnpm -v查看版本信息&#xff0c;结果说找不到cnpm命令 &#xff08;3&#xff…

【Ubuntu20.04+Noetic】UR5e+Gazebo+Moveit

环境准备 创建工作空间 mkdir -p ur5e_ws/src cd ur5e_ws/srcUR机械臂软件包 UR官方没更新最新的noetic的分支,因此安装melodic,并需要改动相关文件。 安装UR的模型配置包,包里面有UR模型文件,moveit配置等: cd ~/ur5e_ws/src git clone -b melodic-devel https://git…

分步搭建HF区块链网络

一.搭建网络规划 采用容器环境&#xff0c;搭建1个排序节点(Orderer)、2个对等节点(Peer)&#xff0c;另外用 一个fabric-cli容器。实训中的绝大部分命令是通过该容器执行的。 容器名称设置 二. 配置HF网络证书 首先docker ps 检查镜像&#xff0c;确保镜像为空 1.生成crypto…

新技术前沿-2024-国内主流AI大模型架构及应用场景深度分析

参考国内主流AI 大模型架构及应用场景深度分析 2024 1 厂商总览 1.1 国外 (1)Open AI:GPT-4【美国旧金山的人工智能研究公司】 GPT-4于2023年3月14日发布,是千亿级参数的多模态预训练模型,能够支持图像和文本的输入。 (2)Anthropic(人类的):Claude【美国人工智能初创公司…

供应链拉动与推动生产方式(供应链维度)

一、推式供应链与拉式供应链的定义 1、推动式供应链 推动式供应链是以制造商为核心企业&#xff0c;根据产品的生产和库存情况&#xff0c;有计划地把商品推销给客户&#xff0c;其驱动力源于供应链上游制造商的生产。在这种运作方式下&#xff0c;供应链上各节点比较松散&am…

探索深度与广度的平衡:迭代加深深度优先搜索技术解析

探索深度与广度的平衡&#xff1a;迭代加深深度优先搜索技术解析 迭代加深深度优先搜索&#xff08;IDDFS&#xff09;的基本原理伪代码C语言实现讨论结论 迭代加深&#xff08;Iterative Deepening Depth-First Search, IDDFS&#xff09;是一种用于解决搜索问题的方法&#x…

前端开发攻略---实现发送手机验证码60s倒计时效果(手机号验证+按钮文字自定义显示+Vue2写法+Vue3写法)

1、演示 2、说明 1、为了便于演示&#xff0c;本示例将在3秒后就再次发送。您可以根据需要自定义此时间间隔。 2、采用最少的变量以满足需求&#xff0c;以减少内存占用。 3、不仅仅局限于按钮情况&#xff0c;也可应用于不禁用按钮的情况&#xff0c;以实现更多的扩展性。 4、…

通过使用XShell工具、Nginx环境实现服务器项目构建与发布

前言&#xff1a; 在信息化和数字化的今天&#xff0c;网站和应用的构建与发布已成为企业发展的重要一环。为了确保项目的顺利上线和稳定运行&#xff0c;选择合适的工具和环境至关重要。本文将详细介绍如何通过XShell工具以及Nginx环境来实现服务器项目的构建与发布&#xff0…
最新文章