设计模式 四、行为设计模式(2)

news2025/4/15 21:15:20

五、状态模式

        1、概述

         状态设计模式是一种行为型设计模式,它允许对象在其内部状态发生时改变其行为,这种模式可以消除大量的条件语句,并将每个状态的行为封装到单独的类中。

        状态模式的主要组成部分如下:
        1)上下文(Context):上下文通常包含一个具体状态的引用,用于维护当前状态,上下文委托给当前对象处理状态相关行为。
        2)抽象状态(State):定义一个接口,用于封装与上下文的特定状态相关的行为。
        3)具体状态(Concrete State):实现抽象状态接口,为具体状态定义行为。每个具体状态类对应一个状态。

        简单示例,假设要模拟一个简易的电视遥控器,具有开启、关闭和调整音量的功能。
        假设不使用设计模式:

public class TV {
    private boolean isOn;
    private int volume;
    public TV() {
        isOn = false;
        volume = 0;
    }
    public void turnOn() {
        // 如果是开启状态
        if (isOn) {
            System.out.println("TV is already on.");
            // 否则打开电视
        } else {
            isOn = true;
            System.out.println("Turning on the TV.");
        }
    }
    public void turnOff() {
        if (isOn) {
            isOn = false;
            System.out.println("Turning off the TV.");
        } else {
            System.out.println("TV is already off.");
        }
    }
    public void adjustVolume(int volume) {
        if (isOn) {
            this.volume = volume;
            System.out.println("Adjusting volume to: " + volume);
        } else {
            System.out.println("Cannot adjust volume, TV is off.");
        }
    }
}
public class Main {
    public static void main(String[] args) {
        TV tv = new TV();
        tv.turnOn();
        tv.adjustVolume(10);
        tv.turnOff();
    }
}

        该例子中我们状态比较少,所以代码看起来也不是很复杂,但是状态如果变多了就会变得不好控制,比如增加换台,快捷键,静音等功能。
        使用状态设计模式之后:
        首先定义抽象状态接口TVState,将每一个修改状态的动作抽象成一个接口:

public interface TVState {
    void turnOn();
    void turnOff();
    void adjustVolume(int volume);
}

        接下来为每个具体的状态创建类,实现TVState接口,例如:创建TVOnState 和 TVOffState 类:

// 在on状态下,去执行以下各种操作
public class TVOnState implements TVState {
    @Override
    public void turnOn() {
        System.out.println("TV is already on.");
    }
    @Override
    public void turnOff() {
        System.out.println("Turning off the TV.");
    }
    @Override
    public void adjustVolume(int volume) {
        System.out.println("Adjusting volume to: " + volume);
    }
}
// 在关机的状态下执行以下的操作
public class TVOffState implements TVState {
    @Override
    public void turnOn() {
        System.out.println("Turning on the TV.");
    }
    @Override
    public void turnOff() {
        System.out.println("TV is already off.");
    }
    @Override
    public void adjustVolume(int volume) {
        System.out.println("Cannot adjust volume, TV is off.");
    }
}

        接下来定义上下文类TV:

public class TV {
    // 当前状态
    private TVState state;
    public TV() {
        state = new TVOffState();
    }
    public void setState(TVState state) {
        this.state = state;
    }
    public void turnOn() {
        // 打开
        state.turnOn();
        // 设置为开机状态
        setState(new TVOnState());
    }
    public void turnOff() {
        // 关闭
        state.turnOff();
        // 设置为关机状态
        setState(new TVOffState());
    }
    public void adjustVolume(int volume) {
        state.adjustVolume(volume);
    }
}

        最后通过以下方式使用这些类:

public class Main {
    public static void main(String[] args) {
        TV tv = new TV();
        tv.turnOn();
        tv.adjustVolume(10);
        tv.turnOff();
    }
}

        这个例子展示了状态模式的基本结构和用法。通过使用状态模式,我们可以更好地组织和管理与特定状态相关的代码。当状态较多时,这种模式的优势就会凸显出来,同时我们在代码时,因为我们会对每个状态进行独立封装,所以也会简化代码编写。

        2、有限状态机

        有限状态机,英文翻译时Flinite State Machine,缩写为FSM,简称状态机,比较官方的说法是:有限状态机是描述对象在它的生命周期内所经历的状态序列,以及如何响应来自外界的各种事件。状态机有3个组成部分:状态(State)、事件(Event)、动作(Action)。其中,事件也成为转移条件(Transition Condition)。事件触发状态的转移及动作的执行,不过,动作不是必须的,也可能只转移状态,不执行任何动作。

        2.1 分支法

        如何实现状态机,总结了三种方式。其中,最简单直接的实现方式是,参照状态转移图,将每一个状态转移。原模原样的直译成代码。这样编写的代码会包含大量的 if - else或 switch-case 分支判断逻辑,甚至是嵌套的分支判断逻辑。所以我们把这种方法暂且命名为分支法:

        下面是一个使用if-else 语句实现的马里奥形态变化的代码示例:

public class Mario {
    private MarioState state;
    public Mario() {
        state = MarioState.SMALL;
    }
    public void handleEvent(Event event) {
        MarioState newState = state;
        // 处理吃蘑菇事件
        if (event == Event.MUSHROOM) {
            if (state == MarioState.SMALL) {
                newState = MarioState.BIG;
            }
        // 处理吃火花事件
        } else if (event == Event.FIRE_FLOWER) {
            if (state == MarioState.BIG) {
                newState = MarioState.FIRE;
            }
        // 处理遇到小怪事件
        } else if (event == Event.ENEMY_ATTACK) {
            if (state == MarioState.BIG) {
                newState = MarioState.SMALL;
            } else if (state == MarioState.FIRE) {
                newState = MarioState.BIG;
            } else if (state == MarioState.SMALL) {
                newState = MarioState.DEAD;
            }
        // 处理掉坑事件
        } else if (event == Event.FALL_INTO_PIT) {
            newState = MarioState.DEAD;
        }
        System.out.printf("从 %s 变为 %s%n", state, newState);
        state = newState;
    }
}
public class MarioDemo {
    public static void main(String[] args) {
        Mario mario = new Mario();
        mario.handleEvent(Event.MUSHROOM); // 变为大马里奥
        mario.handleEvent(Event.FIRE_FLOWER); // 变为火焰马里奥
        mario.handleEvent(Event.ENEMY_ATTACK); // 变为死亡马里奥
    }
}
        在这个示例中,我们使用 if-else 语句来处理状态转换。 handleEvent 方法中,我们根据事件和当前状态的组合来确定新状态 ,并 更新马里奥的状态 。这种实现方法相较于查表法和面向对象实现更为简单,但可能在状态和事件更多的情况下变得难以维护。选择合适的实现方法取决于实际需求和场景。

        2.2 查表法

           该种方法略,不怎么用,可以自己查资料。

        2.3 状态模式

        在查表法的代码实现中,事件触发的动作只是简单的状态或者数值,所以,我们用一个 MarioState类型的二维数组 TRANSITION_TABLE 就能表示,二维数组中的值表示出发事件后的新状态。但是,如果要执行的动作并非这么简单,而是一系列复杂的逻辑操作(比如加减分数、处理位置信息等等),我们就没法用如此简单的二维数组来表示了。这也就是说,查表法的实现方式有一定局限性

        虽然分支逻辑的实现方式不存在这个问题,但它又存在前面讲到的其他问题,比如分支判断逻辑较多,导致代码可读性和可维护性不好等。实际上,针对分支逻辑法存在的问题,我们可以使用状态模式来解决

        状态模式通过将事件触发的状态转移和动作执行,拆分到不同的状态类中,来避免分支判断逻辑。我们还是结合代码来理解这句话。利用状态模式,我们来补全 MarioStateMachine 类,补全后的代码如下所示。

        以下是一个使用 Java 实现的简化版马里奥形态变化的案例代码,我为代码添加了中文注释以便理解:

// 定义事件枚举类型
enum Event {
    // 吃蘑菇,吃火花,遇到小怪,调入深坑
    MUSHROOM, FIRE_FLOWER, ENEMY_ATTACK, FALL_INTO_PIT
}
// 定义马里奥状态接口
interface MarioState {
    void handleEvent(Event event);
}
// 实现死亡马里奥状态
class DeadMario implements MarioState {
    private Mario mario;
    public DeadMario(Mario mario) {
        this.mario = mario;
    }
    @Override
    public void handleEvent(Event event) {
        System.out.println("马里奥已死亡,无法处理事件");
    }
}
// 实现小马里奥状态
class SmallMario implements MarioState {
    private Mario mario;
    public SmallMario(Mario mario) {
        this.mario = mario;
    }
    @Override
    public void handleEvent(Event event) {
        switch (event) {
            case MUSHROOM:
                System.out.println("变为大马里奥");
                mario.setState(new BigMario(mario));
                break;
            case FIRE_FLOWER:
                System.out.println("小马里奥不能直接变为火焰马里奥");
                break;
            case ENEMY_ATTACK:
                System.out.println("小玛丽奥去世了");
                mario.setState(new DeadMario(mario));
                break;
            case FALL_INTO_PIT:
                System.out.println("小玛丽奥去世了");
                mario.setState(new DeadMario(mario));
                break;
        }
    }
}
// 实现大马里奥状态
class BigMario implements MarioState {
    private Mario mario;
    public BigMario(Mario mario) {
        this.mario = mario;
    }
    @Override
    public void handleEvent(Event event) {
        switch (event) {
            case MUSHROOM:
                System.out.println("保持大马里奥");
                break;
            case FIRE_FLOWER:
                System.out.println("变为火焰马里奥");
                mario.setState(new FireMario(mario));
                break;
            case ENEMY_ATTACK:
                System.out.println("变为小马里奥");
                mario.setState(new SmallMario(mario));
                break;
            case FALL_INTO_PIT:
                System.out.println("马里奥去世了");
                mario.setState(new DeadMario(mario));
                break;
        }
    }
}
// 实现火焰马里奥状态
class FireMario implements MarioState {
    private Mario mario;
    public FireMario(Mario mario) {
        this.mario = mario;
    }
    @Override
    public void handleEvent(Event event) {
        switch (event) {
            case MUSHROOM:
                System.out.println("保持火焰马里奥");
                break;
            case FIRE_FLOWER:
                System.out.println("保持火焰马里奥");
                break;
            case ENEMY_ATTACK:
                System.out.println("变为大马里奥");
                mario.setState(new BigMario(mario));
                break;
            case FALL_INTO_PIT:
                System.out.println("马里奥去世了");
                mario.setState(new DeadMario(mario));
                break;
        }
    }
}
// 定义马里奥类,作为状态的上下文
class Mario {
    private MarioState state;
    public Mario() {
        state = new SmallMario(this);
    }
    public void setState(MarioState state) {
        this.state = state;
    }
    public void handleEvent(Event event) {
        state.handleEvent(event);
    }
}
// 测试类
public class MarioDemo {
    public static void main(String[] args) {
        Mario mario = new Mario();
        mario.handleEvent(Event.MUSHROOM); // 变为大马里奥
        mario.handleEvent(Event.FIRE_FLOWER); // 变为火焰马里奥
        mario.handleEvent(Event.ENEMY_ATTACK); // 变为大马里奥
    }
}

        在这个简化示例中,我们定义了 MarioState 接口以及实现了 DeadMario 、SmallMario 、 BigMario FireMario 类,分别表示马里奥的四种形态。每个形态类实现了 handleEvent 方法,用于处理不同的游戏事件并根据有限状态机规 则进行状态转换。

        Mario 类作为状态的上下文,用于管理和切换马里奥的状态。它有一个 setState方法,用于更新当前状态。 handleEvent 方法将事件传递给当前状态,以便根据事件执行相应的状态转换。

        在 MarioDemo 测试类中,我们创建了一个 Mario 实例,并通过调用handleEvent 方法模拟游戏中的事件。通过运行这个测试类,你可以观察到马里奥根据有限状态机的规则在不同形态之间切换。

        这个简化示例展示了如何使用有限状态机来实现马里奥角色的形态变化。在实际游戏开发中,你可能需要考虑更多的事件和状态,以及与游戏引擎或框架集成的方式。不过,这个示例可以帮助你理解有限状态机在游戏中的应用。

六、迭代器模式

        迭代器模式,它用来遍历集合对象,不过,很多编程语言都将迭代器作为一个基础的类库,直接提供出来了。在平时的开发中,特别是业务开发,我们直接使用即可,很少会自己去实现一个迭代器。不过弄懂原理能帮助我们更好的使用这些工具类。

        不怎么用,省略,需要可以自行查询。

        

七、访问者模式

        1、概述和原理

        访问者设计模式(Visitor Pattern)是一种行为型设计模式,它允许你再不修改现有类结构的情况下,为类添加新的操作,这种模式可以实现良好的解耦和扩展性,尤其适用于现有类层次结构中添加新的功能的情况。

        访问者模式主要包含以下角色:
        1. 访问者(Visitor):定义一个访问具体元素的接口,为每种具体元素类型声明一个访问操作。
        2. 具体访问者(ConcreteVisitor):实现访问者接口,为每种具体元素提供具体的访问操作实现。
        3. 元素(Element):定义一个接口,声明接受访问者的方法。
        4. 具体元素(ConcreteElement):实现元素接口,提供接受访问者的具体实现。
        5. 对象结构(ObjectStructure
):包含一个元素集合,提供一个方法以遍历这些元素并让访问者访问它们。

        以下是一个简单的访问者模式示例:

        假设我们有一个表示计算机组件的类层次结构(如 CPU、内存和硬盘等),我们需要为这些组件实现一个功能,比如展示它们的详细信息。使用访问者模式,我们可以将【展示详细信息】的功能与【组件类】分离,从而实现解耦和扩展性。
        1、不同的元素(被访问的对象)可以接收不同的访问者。
        2、不同的访问者会对不同的被访问者产生不同的行为。
        3、如果想要扩展,则独立重新实现访问者接口,产生一个新的具体访问者就可以了。
        4、他实际解耦的是【被访问者】和【对被访问者的操作】。

        简单理解就是不同的访问者,到了同一个被访问对象的家里会干不同的事。这个【事】就是行为,通过访问者模式,我们可以将行为和对象分离解耦,如下图。

        下边是一个使用了访问者模式的案例:
// 访问者接口
interface ComputerPartVisitor {
    // 访问 Computer 对象
    void visit(Computer computer);
    // 访问 Mouse 对象
    void visit(Mouse mouse);
    // 访问 Keyboard 对象
    void visit(Keyboard keyboard);
}
// 具体访问者
class ComputerPartDisplayVisitor implements ComputerPartVisitor {
    // 访问 Computer 对象
    @Override
    public void visit(Computer computer) {
        System.out.println("Displaying Computer.");
    }
    // 访问 Mouse 对象
    @Override
    public void visit(Mouse mouse) {
        System.out.println("Displaying Mouse.");
    }
    // 访问 Keyboard 对象
    @Override
    public void visit(Keyboard keyboard) {
        System.out.println("Displaying Keyboard.");
    }
}
// 元素接口
interface ComputerPart {
    // 接受访问者的访问
    void accept(ComputerPartVisitor computerPartVisitor);
}
// 具体元素
class Computer implements ComputerPart {
    // 子元素数组
    ComputerPart[] parts;
    public Computer() {
        // 初始化子元素数组
        parts = new ComputerPart[]{new Mouse(), new Keyboard()};
    }
    // 接受访问者的访问
    @Override
    public void accept(ComputerPartVisitor computerPartVisitor) {
        // 遍历所有子元素并接受访问者的访问
        for (int i = 0; i < parts.length; i++) {
            parts[i].accept(computerPartVisitor);
        }
        // 访问 Computer 对象本身
        computerPartVisitor.visit(this);
    }
}
// 具体元素:鼠标
class Mouse implements ComputerPart {
    // 接受访问者的访问
    @Override
    public void accept(ComputerPartVisitor computerPartVisitor) {
        // 访问 Mouse 对象
        computerPartVisitor.visit(this);
    }
}
// 具体元素:键盘
class Keyboard implements ComputerPart {
    // 接受访问者的访问
    @Override
    public void accept(ComputerPartVisitor computerPartVisitor) {
        // 访问 Keyboard 对象
        computerPartVisitor.visit(this);
    }
}
// 客户端代码
public class VisitorPatternDemo {
    public static void main(String[] args) {
        // 创建一个 Computer 对象
        ComputerPart computer = new Computer();
        // 创建一个具体访问者
        ComputerPartVisitor visitor = new ComputerPartDisplayVisitor();
        // 让 Computer 对象接受访问者的访问
        computer.accept(visitor);
    }
}

        在这个示例中,我们定义了一个表示计算机组件的类层次结构,包括 Computer 、Mouse 和 Keyboard 。这些类实现了 ComputerPart 接口,该接口声明了一个接受访问者的方法。我们还定义了一个 ComputerPartVisitor 接口,用于访问这些计算机组件,并为每种组件类型声明了一个访问操作。

        ComputerPartDisplayVisitor 类实现了 ComputerPartVisitor 接口,为每种计算机组件提供了展示详细信息的功能。在客户端代码中,我们创建了一个Computer 对象和一个 ComputerPartDisplayVisitor 对象。当我们调用computer.accept() 方法时,计算机的所有组件都会被访问者访问,并显示相应的详细信息。

        这个示例展示了如何使用访问者模式将功能与类结构分离,实现解耦和扩展性。如果我们需要为计算机组件添加新功能,只需创建一个新的访问者类,而无需修改现有的组件类。这使得在不影响现有代码的情况下,为系统添加新功能变得容易。

// 添加一个更新计算机部件的访问者实现
class ComputerPartUpdateVisitorImpl implements ComputerPartVisitor {
    // 访问 Computer 对象并执行更新操作
    @Override
    public void visit(Computer computer) {
        System.out.println("Updating Computer.");
    }
    // 访问 Mouse 对象并执行更新操作
    @Override
    public void visit(Mouse mouse) {
        System.out.println("Updating Mouse.");
    }
    // 访问 Keyboard 对象并执行更新操作
    @Override
    public void visit(Keyboard keyboard) {
        System.out.println("Updating Keyboard.");
    }
}
// 客户端代码,几乎不用任何修改
public class VisitorPatternDemo {
    public static void main(String[] args) {
        // 创建一个 Computer 对象
        ComputerPart computer = new Computer();
        // 创建一个具体访问者
        ComputerPartVisitor visitor = new ComputerPartUpdateVisitorImpl();
        // 让 Computer 对象接受访问者的访问
        computer.accept(visitor);
    }
}

        访问者模式可以算是 23 种经典设计模式中最难理解的几个之一。因为它难理解、难实现,应用它会导致代码的可读性、可维护性变差,所以,访问者模式在实际的软件开发中很少被用到,在没有特别必要的情况下,建议你不要使用访问者模式。

        2、使用场景

        2.1 抽象语法树

        访问者模式在实际项目中的一个常见使用场景是处理抽象语法树(AST)。例如,在编译器或解释器中,我们需要处理不同类型的语法结构,如声明、表达式、循环等。 使用访问者模式,我们可以将处理这些结构的功能与结构类分离,实现解耦和扩展性。
        以下是一个简单的示例,展示了如何使用访问者模式处理抽象语法树

// AST 节点基类
abstract class AstNode {
    // 接受访问者的方法
    abstract void accept(AstVisitor visitor);
}
// 访问者接口
interface AstVisitor {
    // 访问表达式节点的方法
    void visit(ExpressionNode node);
    // 访问数字节点的方法
    void visit(NumberNode node);
    // 访问加法节点的方法
    void visit(AdditionNode node);
// 省略其他节点
}
// 数字节点,表示一个整数值
class NumberNode extends AstNode {
    int value;
    // 构造方法,接收一个整数作为值
    NumberNode(int value) {
        this.value = value;
    }
    // 实现基类的 accept 方法,接受访问者
    void accept(AstVisitor visitor) {
        visitor.visit(this);
    }
}
// 加法节点,表示两个子节点的相加
class AdditionNode extends AstNode {
    AstNode left;
    AstNode right;
    // 构造方法,接收两个子节点
    AdditionNode(AstNode left, AstNode right) {
        this.left = left;
        this.right = right;
    }
    // 实现基类的 accept 方法,接受访问者
    void accept(AstVisitor visitor) {
        visitor.visit(this);
    }
}
// 表达式节点,包含一个子节点
class ExpressionNode extends AstNode {
    AstNode node;
    // 构造方法,接收一个子节点
    ExpressionNode(AstNode node) {
        this.node = node;
    }
    // 实现基类的 accept 方法,接受访问者
    void accept(AstVisitor visitor) {
        visitor.visit(this);
    }
}
        现在,我们可以创建一个实现了 AstVisitor 接口的类,用于遍历 AST 并计算其结果:
class AstEvaluator implements AstVisitor {
    int result;
    AstEvaluator() {
        result = 0;
    }
    void visit(ExpressionNode node) {
        node.node.accept(this);
    }
    void visit(NumberNode node) {
        result = node.value;
    }
    void visit(AdditionNode node) {
        node.left.accept(this);
        int leftValue = result;
        node.right.accept(this);
        int rightValue = result;
        result = leftValue + rightValue;
    }
}

        最后,我们可以使用这个访问者类计算一个简单的 AST

public class Main {
    public static void main(String[] args) {
        // 创建一个简单的 AST:(2 + 3)
        AstNode ast = new ExpressionNode(
                new AdditionNode(
                        new NumberNode(2),
                        new NumberNode(3)
                )
        );
        // 创建一个访问者实例
        AstEvaluator evaluator = new AstEvaluator();
        // 使用访问者计算 AST 的结果
        ast.accept(evaluator);
        // 输出计算结果
        System.out.println("AST 的结果是: " + evaluator.result);
    }
}
        这个示例将输出 AST 的结果是 : 5

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

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

相关文章

FEA 仿真助力高速连接器设计中的信号完整性

各行各业高速信号软件和硬件的快速发展&#xff0c;带来了更高的频率和带宽。因此&#xff0c;对连接器组件的整体性能要求也更加严格。同时&#xff0c;器件和封装形式、互连以及系统内其他设备的小型化也带来了额外的设计挑战。所有这些都对信号传输完整性产生重大影响。 高速…

yum的基本操作和vim指令

在我们的手机端或者Windows上下载软件&#xff0c;可以在相应的应用商店或者官网进行下载&#xff0c;这样对于用户来说十分的方便和便捷。而在Linux上&#xff0c;也有类似的安装方式&#xff0c;我们来一一了解一下。 Linux安装软件的3种方法 源代码安装 在Linux下安装软件…

Qt触摸屏隐藏鼠标指针

Qt触摸屏隐藏鼠标指针 Chapter1 Qt触摸屏隐藏鼠标指针 Chapter1 Qt触摸屏隐藏鼠标指针 使用Qt开发的屏幕软件HMI不需要显示鼠标&#xff0c;qt设置&#xff0c;可以在只启动HMI的时候隐藏光标&#xff0c;退出时再显示。 1.如果只希望在某个 widget 中不显示鼠标指针&#xf…

LangGraph——Agent AI的持久化状态

LangGraph 内置了一个持久化层&#xff0c;通过检查点(checkpointer)机制实现。当你使用检查点器编译图时&#xff0c;它会在每个超级步骤(super-step)自动保存图状态的检查点。这些检查点被存储在一个线程(thread)中&#xff0c;可在图执行后随时访问。由于线程允许在执行后访…

【双指针】专题:LeetCode 1089题解——复写零

复写零 一、题目链接二、题目三、算法原理1、先找到最后一个要复写的数——双指针算法1.5、处理一下边界情况2、“从后向前”完成复写操作 四、编写代码五、时间复杂度和空间复杂度 一、题目链接 复写零 二、题目 三、算法原理 解法&#xff1a;双指针算法 先根据“异地”操…

【C++初学】C++核心编程(一):内存管理和引用

前言 在C的世界里&#xff0c;面向对象编程&#xff08;OOP&#xff09;是核心中的核心。它不仅是一种编程范式&#xff0c;更是一种思考问题的方式。本文将带你从C的内存分区模型出发&#xff0c;深入探讨引用、函数、类和对象、继承、多态以及文件操作等核心概念。通过丰富的…

(PC+WAP)大气滚屏网站模板 电气电力设备网站源码下载

源码介绍 (PCWAP)大气滚屏网站模板 电气电力设备网站源码下载。PbootCMS内核开发的网站模板&#xff0c;该模板适用于滚屏网站模板、电气电力设备网站源码等企业&#xff0c;当然其他行业也可以做&#xff0c;只需要把文字图片换成其他行业的即可&#xff1b;PCWAP&#xff0c…

笔试专题(九)

文章目录 十字爆破&#xff08;暴力&#xff09;题解代码 比那名居的桃子&#xff08;滑动窗口/前缀和&#xff09;题解代码 分组&#xff08;暴力枚举 优化二分&#xff09;题解代码 十字爆破&#xff08;暴力&#xff09; 题目链接 题解 1. 暴力 预处理 2. 如果单纯的暴…

3 VS Code 配置优化与实用插件推荐:settings.json 详解、CodeGeeX 智能编程助手及插件离线安装方法

1 优化 settings.json 文件 1.1 settings.json 简介 settings.json 是 VS Code 的核心配置文件&#xff0c;用于存储用户的个性化设置和偏好。通过该文件&#xff0c;用户可以自定义和覆盖 VS Code 的默认行为&#xff0c;包括但不限于以下方面&#xff1a; 编辑器外观&#…

TA学习之路——1.6 PC手机图形API介绍

1前言 电脑的工作原理&#xff1a;电脑是由各种不同的硬件组成&#xff0c;由驱动软件驱使硬件进行工作。所有的软件工程师都会直接或者间接的使用到驱动。 定义&#xff1a;是一个图形库&#xff0c;用于渲染2D、3D矢量图形的跨语言、跨平台的应用程序接口&#xff08;API)。…

Matlab 调制信号和fft变换

1、内容简介 Matlab 194-调制信号和fft变换 可以交流、咨询、答疑 2、内容说明 略 3、仿真分析 略 4、参考论文 略

100M/1000M 以太网静电浪涌防护方案

方案简介 以太网是一种生产较早且广泛应用的局域网通讯方式&#xff0c;同时也是一种协议&#xff0c;其核 心在于实现区域内&#xff08;如办公室、学校等&#xff09;的网络互联。根据数据传输速度的不同&#xff0c;以 太网大致可以划分为几个等级&#xff1a;标准以太网…

C语言中while的相关题目

一、题目引入 以下程序中,while循环的循环次数是多少次? 二、代码分析 首先要明确的一点 while循环是当循环条件为真 就会一直循环 不会停止 while中i是小于10的 说明i可以取到0 1 2 3 4 5 6 7 8 9 进入第一个if判断i小于1为真时执行continue i0是为真的 执行continue 后…

「Unity3D」图片导入选项取消Read/Write,就无法正确显示导入大小,以及Addressable打包无法正确显示的问题

如果在Edit -> Project Settings -> Editor中的“Load texture data on demand”勾选&#xff0c;就会让图片导入设置中&#xff0c;不勾选Read/Write&#xff0c;就无法正确显示纹理的大小数字。 更进一步的问题是&#xff0c;使用Addressable打包的时候&#xff0c; 如…

Xcode为不同环境配置不同的环境变量

一般有三种方式&#xff1a; 一、通过多Target 二、通过scheme,也就是多configurations 三、通过.xcconfig文件 先来看第二种方式&#xff1a;通过scheme,也就是多configurations,包括自定义User-settings 第一步&#xff1a;增加configurations,Xcode默认为我们生成了…

阿里通义实验室发布图片数字人项目LAM,实现高保真重建

简介 LAM项目结合了3D Gaussian Splatting&#xff08;高斯点云渲染&#xff09;和大规模预训练模型的优势&#xff0c;解决了传统头部重建方法效率低、依赖多数据的痛点。其背景源于AI生成内容&#xff08;AIGC&#xff09;领域对实时、高保真3D头像生成的需求&#xff0c;尤其…

镜像端口及观察端口的配置

配好路由器的各个接口的IP PC1ping PC3的IP&#xff0c;在路由器中抓2/0/0端口的包&#xff0c;可观察到无结果 输入observe-port interface g 2/0/0 命令配置观察端口 输入mirror to observe-port both命令 &#xff08;其中both表示接收来去的数据包&#xff0c;inboun…

STM32——I2C通讯(软件模拟)

I2C概念 I2C:Inter-Integrated Circuit&#xff08;内部集成电路&#xff09; Philps公司80年代初期开发的&#xff0c;引脚少&#xff0c;硬件实现简单&#xff0c;可扩展性广泛地使用在系统内多个集成电路&#xff08;IC&#xff09;间的低速通讯 简单的双向两线制总线协议…

JetBrains Terminal 又发布新架构,Android Studio 将再次迎来新终端

不到一年的时间&#xff0c;JetBrains 又要对 Terminal 「大刀阔斧」&#xff0c;本次发布的新终端是重构后的全新的架构&#xff0c;而上一次终端大调整还是去年 8 月的 v2024.2 版本&#xff0c;并且在「Android Studio Ladybug | 2024.2.1」也被引入。 不知道你们用不用内置…

论文:Generalized Category Discovery with Large Language Models in the Loop

论文下载地址&#xff1a;Generalized Category Discovery with Large Language Models in the Loop - ACL Anthology 1、研究背景 尽管现代机器学习系统在许多任务上取得了优异的性能&#xff0c;绝大多数都遵循封闭世界的设置&#xff0c;假设训练和测试数据来自同一组预定义…