【备忘录模式】设计模式系列:掌握状态回溯的艺术(设计详解)

news2024/11/24 8:42:30

文章目录

  • 备忘录设计模式详解
    • 引言
    • 1. 设计模式概述
    • 2. 备忘录模式的基本概念
      • 2.1 备忘录模式的定义
      • 2.2 备忘录模式的关键角色
    • 3. 备忘录模式的实现原理
      • 3.1 备忘录模式的工作流程
      • 3.2 模式的优缺点分析
      • 3.3 与其他模式的对比
    • 4. 实际案例分析
      • 4.1 游戏状态保存与恢复
      • 4.2 文档编辑器撤销功能
      • 4.3 图形用户界面的状态管理
    • 5. 设计考虑
      • 5.1 封装性的重要性
      • 5.2 内部状态与外部状态的区别
      • 5.3 对象的生命周期管理
    • 6. Java实现备忘录模式
      • 6.1 Java代码示例
      • 6.2 关键类和接口的定义
      • 6.3 测试和验证
    • 7. 性能考量
    • 8. 备忘录模式的变体
      • 8.1 有限历史记录
      • 8.2 自动保存与定时备份
      • 8.3 多级撤销
    • 9. 模式组合
      • 9.1 与命令模式结合
      • 9.2 与迭代器模式结合
      • 9.3 与观察者模式结合
    • 10. 最佳实践
      • 10.1 如何避免内存泄漏
      • 10.2 使用工厂模式创建备忘录对象
      • 10.3 避免过度使用备忘录模式
    • 11. 常见问题及解答
    • 12 结论


备忘录设计模式详解


引言

软件开发中的挑战
在软件开发过程中,开发人员经常面临各种挑战,如需求变更、复杂性增加、性能瓶颈等。为了应对这些挑战,开发者需要采用一系列有效的技术和方法。其中一种重要的技术就是设计模式,它能够帮助解决特定的问题并提高代码的质量。

设计模式的重要性
设计模式是一套被广泛接受的解决方案,用于解决软件设计中经常出现的问题。它们不仅简化了代码的编写过程,还提高了系统的可维护性和可扩展性。通过使用设计模式,开发者可以学习到前辈们的经验教训,避免重复造轮子,从而加快开发速度。

备忘录模式的简介
备忘录模式是一种行为型设计模式,它允许在不破坏封装性的前提下捕获一个对象的内部状态,并在该对象之外保存这个状态。这样以后就可以将该对象恢复到原先保存的状态。这种模式特别适用于需要撤销或恢复操作的情况,比如实现类似“撤销”功能的应用程序。

1. 设计模式概述

1.1 设计模式定义
设计模式是在软件设计过程中反复出现的问题的解决方案。这些解决方案并不是具体的代码,而是一种通用的描述,用来说明如何在特定情况下解决问题。设计模式可以被看作是一种模板,帮助开发者更好地组织代码,并使代码更易于理解和复用。

1.2 常见的设计模式分类
设计模式通常分为三大类:

  1. 创建型模式:关注于对象的创建机制,使得我们可以根据具体情况创建对象。
  2. 结构型模式:关注于如何组合类或对象来获得更大的结构。
  3. 行为型模式:关注于算法和对象间职责的分配。

1.3 设计模式的应用场景
设计模式适用于多种不同的情况,包括但不限于:

  • 当你需要重用相同的解决方案来解决相同的问题时。
  • 当你需要简化复杂的代码结构,使其更加清晰易懂时。
  • 当你需要提高代码的可维护性和可扩展性时。
  • 当你需要提高代码的复用性,减少冗余时。

2. 备忘录模式的基本概念

2.1 备忘录模式的定义

备忘录模式允许在不破坏封装性的前提下捕获一个对象的内部状态,并在该对象之外保存这个状态。这样以后就可以将该对象恢复到原先保存的状态。它提供了一种回滚机制,可以撤销到之前的状态。

2.2 备忘录模式的关键角色

Originator (发起者)
发起者是一个包含有重要内部状态的对象。当需要保存当前状态时,发起者会创建一个备忘录对象,并在需要时使用该备忘录恢复状态。

Memento (备忘录)
备忘录对象负责存储发起者的内部状态。为了保持封装性,备忘录对象通常不允许发起者以外的对象访问其内部状态。

Caretaker (管理者)
管理者负责保存和管理备忘录对象。它并不对备忘录的内容感兴趣,只负责提供保存和获取备忘录的方法。
在这里插入图片描述


3. 备忘录模式的实现原理

3.1 备忘录模式的工作流程

  1. 创建备忘录:当发起者需要保存当前状态时,它创建一个备忘录对象,并将当前的内部状态复制到备忘录中。
  2. 保存备忘录:管理者接收备忘录对象,并将其保存在某个容器中,以备后续使用。
  3. 恢复状态:当需要恢复到先前的状态时,发起者从管理者处请求备忘录,并使用备忘录中的信息恢复自己的状态。

3.2 模式的优缺点分析

优点:

  • 封装性:备忘录模式保护了发起者的内部状态,因为备忘录对外隐藏了这些状态,只有发起者本身才能访问。
  • 灵活性:备忘录模式提供了一种灵活的方式来恢复状态,这对于需要撤销或恢复功能的应用程序非常有用。
  • 易于实现:备忘录模式的概念简单,实现起来也相对容易。

缺点:

  • 内存消耗:如果应用频繁地保存备忘录,则可能会导致较大的内存开销,尤其是在状态较大的情况下。
  • 性能问题:频繁地创建和销毁备忘录可能会带来一定的性能开销。

3.3 与其他模式的对比

  • 与命令模式的对比:命令模式主要用于封装一个请求作为对象,以便使用不同的请求、队列或者日志请求。备忘录模式则侧重于保存和恢复状态。
  • 与迭代器模式的对比:迭代器模式提供了一种访问集合元素的方法,而不会暴露底层表示。备忘录模式则专注于对象状态的保存和恢复。
  • 与观察者模式的对比:观察者模式定义了对象之间的一对多依赖关系,当一个对象的状态发生改变时,所有依赖它的对象都会得到通知并自动更新。备忘录模式则用于在对象之间传递状态信息。

4. 实际案例分析

4.1 游戏状态保存与恢复

在游戏开发中,备忘录模式可以用于保存玩家的游戏进度,例如角色的位置、生命值、装备等。当玩家想要返回到某个之前的存档点时,可以通过备忘录恢复游戏状态。

4.2 文档编辑器撤销功能

文档编辑器中的撤销功能通常使用备忘录模式实现。每当用户进行一次编辑操作,就会创建一个备忘录来保存当前文档的状态。用户可以撤销到之前的状态,只需从备忘录中恢复文档状态即可。

4.3 图形用户界面的状态管理

在图形用户界面(GUI)应用程序中,备忘录模式可以用来保存用户的界面配置,例如窗口大小、位置、打开的标签页等。这样用户可以在退出后再次打开应用程序时恢复到之前的状态。

5. 设计考虑

5.1 封装性的重要性

封装是面向对象编程的一个核心原则,它保证了对象的内部状态不会被外部直接访问。在备忘录模式中,发起者对象的内部状态被封装在备忘录对象中,这样就防止了外部对象直接修改这些状态,从而保护了数据的安全性和完整性。

5.2 内部状态与外部状态的区别

  • 内部状态:指的是那些只对发起者有意义的状态,不应该被外部对象访问或修改。这些状态通常是通过备忘录对象来保存的。
  • 外部状态:是指那些在备忘录外部并且在恢复时不需要重新设置的状态。这些状态通常由发起者自行管理,不在备忘录中保存。

5.3 对象的生命周期管理

在备忘录模式中,需要考虑备忘录对象的生命周期管理。一旦不再需要某个备忘录,就应该及时释放,以免占用不必要的内存资源。同时,也需要考虑如何有效地管理多个备忘录,特别是在需要保存多个版本的状态时。


6. Java实现备忘录模式

6.1 Java代码示例

以下是一个简单的Java实现示例,展示了备忘录模式的基本组件:

// Memento class
class Memento {
    private String state;

    public Memento(String state) {
        this.state = state;
    }

    public String getState() {
        return state;
    }
}

// Originator class
class Originator {
    private String state;

    public void setState(String state) {
        this.state = state;
    }

    public String getState() {
        return state;
    }

    public Memento createMemento() {
        return new Memento(state);
    }

    public void restoreMemento(Memento memento) {
        this.state = memento.getState();
    }
}

// Caretaker class
class Caretaker {
    private List<Memento> mementos = new ArrayList<>();

    public void addMemento(Memento memento) {
        mementos.add(memento);
    }

    public Memento getMemento(int index) {
        return mementos.get(index);
    }
}

public class Main {
    public static void main(String[] args) {
        Originator originator = new Originator();
        Caretaker caretaker = new Caretaker();

        originator.setState("State #1");
        caretaker.addMemento(originator.createMemento());

        originator.setState("State #2");
        caretaker.addMemento(originator.createMemento());

        originator.setState("State #3");
        caretaker.addMemento(originator.createMemento());

        System.out.println("Current State: " + originator.getState());
        originator.restoreMemento(caretaker.getMemento(1));
        System.out.println("Restored State: " + originator.getState());
    }
}

6.2 关键类和接口的定义

  • Memento:用于存储发起者的状态。
  • Originator:包含状态的对象,可以创建备忘录并恢复状态。
  • Caretaker:管理备忘录的类,保存和提供备忘录。

6.3 测试和验证

测试主要涉及创建备忘录、保存备忘录以及恢复状态的过程。可以通过单元测试来验证每个步骤是否正确执行,确保状态的保存和恢复功能正常工作。


7. 性能考量

7.1 内存使用优化

  • 减少备忘录的数量:只保留最近的几个备忘录,或者根据实际需求定期清除旧的备忘录。
  • 压缩备忘录:对于大型状态,可以考虑使用序列化技术来减小备忘录的大小。
  • 按需加载:只在需要的时候加载备忘录,而不是一开始就全部加载到内存中。

7.2 多线程环境下的考虑

  • 同步访问:在多线程环境中,确保对备忘录的访问是线程安全的。可以使用锁机制来控制并发访问。
  • 线程局部存储:如果可能,使用线程局部存储来存储备忘录,以避免多线程间的竞争条件。

7.3 状态持久化策略

  • 文件系统:将备忘录序列化到磁盘文件中,以供之后使用。
  • 数据库存储:使用数据库来存储备忘录,特别是当需要长期保存状态时。
  • 缓存策略:利用缓存机制来提高备忘录的读取速度,减少磁盘I/O操作。

8. 备忘录模式的变体

8.1 有限历史记录

在某些情况下,我们可能希望限制备忘录的数量,以节省内存空间。这可以通过实现一个有限的历史记录列表来实现,当列表达到最大容量时,最旧的备忘录将被删除。

// LimitedHistoryCaretaker class
class LimitedHistoryCaretaker {
    private int maxHistorySize;
    private List<Memento> mementos = new ArrayList<>();

    public LimitedHistoryCaretaker(int maxHistorySize) {
        this.maxHistorySize = maxHistorySize;
    }

    public void addMemento(Memento memento) {
        if (mementos.size() >= maxHistorySize) {
            mementos.remove(0); // Remove the oldest memento
        }
        mementos.add(memento);
    }

    public Memento getMemento(int index) {
        return mementos.get(index);
    }
}

8.2 自动保存与定时备份

自动保存功能可以在特定的时间间隔内自动保存当前状态为备忘录。这种方式可以减少用户手动保存的操作,同时也能够在系统崩溃时帮助用户恢复未保存的工作。

// AutoSaveCaretaker class
class AutoSaveCaretaker extends Thread {
    private Originator originator;
    private Caretaker caretaker;
    private long interval; // Time interval in milliseconds

    public AutoSaveCaretaker(Originator originator, Caretaker caretaker, long interval) {
        this.originator = originator;
        this.caretaker = caretaker;
        this.interval = interval;
    }

    @Override
    public void run() {
        while (true) {
            try {
                Thread.sleep(interval);
                caretaker.addMemento(originator.createMemento());
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

8.3 多级撤销

多级撤销允许用户撤销多个操作。这可以通过保存多个备忘录并在撤销时逐个恢复它们来实现。

// MultiLevelUndoCaretaker class
class MultiLevelUndoCaretaker {
    private List<Memento> mementos = new ArrayList<>();
    private int current = -1;

    public void addMemento(Memento memento) {
        mementos.add(++current, memento);
        mementos.subList(current + 1, mementos.size()).clear(); // Clear future states
    }

    public Memento undo() {
        if (current > 0) {
            return mementos.get(--current);
        }
        return null;
    }

    public Memento redo() {
        if (current < mementos.size() - 1) {
            return mementos.get(++current);
        }
        return null;
    }
}

9. 模式组合

9.1 与命令模式结合

备忘录模式可以与命令模式结合使用,以支持撤销和重做功能。在这种组合中,每个命令都可以保存一个备忘录,在撤销时恢复到命令执行前的状态。

// Command interface
interface Command {
    void execute();
    Memento createMemento();
    void restoreMemento(Memento memento);
}

// ConcreteCommand class
class ConcreteCommand implements Command {
    private Originator originator;
    private Memento previousState;

    public ConcreteCommand(Originator originator) {
        this.originator = originator;
    }

    @Override
    public void execute() {
        previousState = originator.createMemento();
        originator.setState("New State");
    }

    @Override
    public Memento createMemento() {
        return previousState;
    }

    @Override
    public void restoreMemento(Memento memento) {
        originator.restoreMemento(memento);
    }
}

9.2 与迭代器模式结合

迭代器模式可以用来遍历备忘录列表,这样可以更容易地实现撤销和重做功能。

// Iterator interface
interface Iterator {
    boolean hasNext();
    Memento next();
}

// ListIterator class
class ListIterator implements Iterator {
    private List<Memento> mementos;
    private int position;

    public ListIterator(List<Memento> mementos) {
        this.mementos = mementos;
        this.position = 0;
    }

    @Override
    public boolean hasNext() {
        return position < mementos.size();
    }

    @Override
    public Memento next() {
        if (hasNext()) {
            return mementos.get(position++);
        }
        return null;
    }
}

9.3 与观察者模式结合

观察者模式可以用来通知其他对象备忘录的变化,例如在自动保存时通知用户状态已保存。

// Observer interface
interface Observer {
    void update(Memento memento);
}

// Observable interface
interface Observable {
    void addObserver(Observer observer);
    void removeObserver(Observer observer);
    void notifyObservers(Memento memento);
}

// ObservableCaretaker class
class ObservableCaretaker implements Observable {
    private List<Observer> observers = new ArrayList<>();

    @Override
    public void addObserver(Observer observer) {
        observers.add(observer);
    }

    @Override
    public void removeObserver(Observer observer) {
        observers.remove(observer);
    }

    @Override
    public void notifyObservers(Memento memento) {
        for (Observer observer : observers) {
            observer.update(memento);
        }
    }

    public void addMemento(Memento memento) {
        notifyObservers(memento);
    }
}

10. 最佳实践

10.1 如何避免内存泄漏

为了避免内存泄漏,需要注意以下几点:

  • 及时清理:当不再需要备忘录时,应及时将其从内存中移除。
  • 引用计数:使用引用计数来管理备忘录对象的生命周期。
  • 弱引用:使用弱引用或软引用来存储备忘录对象,这样当内存紧张时,垃圾回收器可以自动回收这些对象。

10.2 使用工厂模式创建备忘录对象

使用工厂模式可以统一备忘录的创建过程,有助于管理备忘录的不同类型或状态。

// MementoFactory class
class MementoFactory {
    public static Memento createMemento(String state) {
        return new Memento(state);
    }
}

10.3 避免过度使用备忘录模式

虽然备忘录模式非常有用,但也应注意不要过度使用,否则可能会导致不必要的内存消耗。在决定使用备忘录模式之前,应评估以下因素:

  • 需求分析:确定确实需要撤销/恢复功能。
  • 性能考量:评估备忘录模式对性能的影响。
  • 替代方案:考虑是否有其他模式或技术可以更高效地解决问题。

11. 常见问题及解答

如何处理大量备忘录对象
当需要处理大量的备忘录对象时,可以采取以下措施:

  • 限制备忘录数量:仅保存最近的几个备忘录,以减少内存占用。
  • 使用缓存策略:使用缓存机制来临时存储备忘录,只在真正需要时才将其加载到内存中。
  • 按需加载:只在需要时加载备忘录,而不是一开始就全部加载到内存中。

是否应该使用序列化来保存备忘录
使用序列化来保存备忘录可以有效减少内存占用,特别是在备忘录包含大量数据时。序列化可以将备忘录转换为磁盘上的文件,这样可以显著降低内存使用量。但是,需要注意的是序列化和反序列化的性能开销,特别是在频繁进行这些操作时。

如何在分布式系统中使用备忘录模式
在分布式系统中使用备忘录模式时,需要考虑以下几个方面:

  • 一致性:确保备忘录在所有节点上都是一致的,这可能需要使用分布式事务或其他一致性协议。
  • 状态同步:使用消息队列或发布/订阅模型来同步备忘录状态。
  • 容错机制:设计容错机制以处理节点故障,例如使用副本集来存储备忘录。

12 结论

备忘录模式在软件工程中的价值
备忘录模式提供了一种优雅的方式来处理对象状态的保存和恢复问题,尤其适用于需要撤销或恢复操作的应用程序。它不仅可以提高代码的可维护性和可扩展性,还可以简化实现复杂功能(如撤销/重做功能)的过程。

未来的研究方向
未来的研究可以集中在以下几个方面:

  • 性能优化:研究更高效的备忘录管理和存储策略,以减少内存使用和提高性能。
  • 分布式环境下的应用:探索备忘录模式在分布式系统中的应用场景和技术挑战。
  • 模式组合:探索备忘录模式与其他设计模式的更多组合方式,以解决更复杂的问题。

本文详细介绍了23种设计模式的基础知识,帮助读者快速掌握设计模式的核心概念,并找到适合实际应用的具体模式:
【设计模式入门】设计模式全解析:23种经典模式介绍与评级指南(设计师必备)

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

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

相关文章

19529 照明灯安装

### 详细分析 这个问题可以通过二分查找和贪心算法来解决。我们需要找到一个最大值&#xff0c;使得在这个最大值下&#xff0c;能够在给定的坐标上安装 k 个照明灯&#xff0c;并且相邻的照明灯之间的距离至少为这个最大值。 ### 思路 1. **排序**&#xff1a;首先对给定的…

S3C2440中断处理

一、中断处理机制概述 中断是CPU在执行程序过程中&#xff0c;遇到急需处理的事件时&#xff0c;暂时停止当前程序的执行&#xff0c;转而执行处理该事件的中断服务程序&#xff0c;并在处理完毕后返回原程序继续执行的过程。S3C2440提供了丰富的中断源&#xff0c;包括内部中…

微信小程序:开发工具修改js编译后还是旧的js逻辑

1、清理所有缓存&#xff0c;重新导入项目 2、语法存在问题无法编译,导致内存堆积&#xff0c;无法自动编译 3、npm 存在问题&#xff0c;可以重新构建 4、有时候编译器也没报错都是一切正常&#xff0c;但是编译后依然不是最新。这个时候需要考虑下电脑是否存在问题&#xff0…

使用gitee存储项目

gitee地址&#xff1a;Gitee - 基于 Git 的代码托管和研发协作平台 创建gitee远程仓库 将远程仓库内容拉取到本地仓库 复制下面这个地址 通过小乌龟便捷推送拉取代码&#xff1a;https://blog.csdn.net/m0_65520060/article/details/140091437

Ubuntu | 解决 VMware 中 Ubuntu 虚拟机磁盘空间不足的问题

目录 一、存在的问题二、解决的步骤第一步&#xff1a;扩展磁盘空间第二步&#xff1a;查看磁盘空间使用情况第三步&#xff1a;安装分区工具第四步&#xff1a;启动分区工具第五步&#xff1a;修改挂载文件夹的读写权限第六步&#xff1a;扩展文件系统大小第七步&#xff1a;验…

Prometheus2:被监控机器安装node_exporter与配置

1. 下载node_exporter [rootlocalhost ~]# wget https://github.com/prometheus/node_exporter/releases/download/v1.8.2/node_exporter-1.8.2.linux-amd64.tar.gz 2. 解压缩 [rootlocalhost ~]# tar -zxvf node_exporter-1.8.2.linux-amd64.tar.gz 3. 复制到/usrl/local路…

sed命令用法与案例

在Linux操作系统中&#xff0c;sed&#xff08;stream editor&#xff09;是一种功能强大的文本处理工具&#xff0c;用于执行文本的查找、替换、删除、新增等操作。sed命令以其简洁的语法和高效的执行速度&#xff0c;在自动化脚本和文本处理中扮演着重要角色。本文将探讨sed命…

探索串行通信的奥秘:Python中的pyserial库

文章目录 探索串行通信的奥秘&#xff1a;Python中的pyserial库背景&#xff1a;为何选择pyserial&#xff1f;pyserial是什么&#xff1f;如何安装pyserial&#xff1f;pyserial的五个简单函数场景应用&#xff1a;pyserial在实际中的使用常见bug及解决方案总结 探索串行通信的…

HR招聘,如何解决招聘需求不明确的问题

在HR招聘过程中&#xff0c;遇到招聘需求不明确的问题时&#xff0c;可以通过一系列措施来明确需求&#xff0c;提高招聘效率和质量。同时&#xff0c;在线人才测评、职业性格测试、认知能力测试和心理健康测试等工具也可以作为辅助手段&#xff0c;帮助HR更准确地评估候选人。…

【大模型从入门到精通33】开源库框架LangChain RAG 系统中的问答技术3

这里写目录标题 理论问答过程的三个主要阶段传递文档片段至 LM 上下文窗口的局限性及策略向量数据库的重要性RetrievalQA 链的作用MapReduce 与 Refine 的区别分布式系统中的实际考量实验的重要性RetrievalQA 链的主要限制对话记忆的重要性 实践初始化向量数据库设置 Retrieval…

GD32双路CAN踩坑记录

GD32双路CAN踩坑记录 目录 GD32双路CAN踩坑记录1 问题描述2 原因分析3 解决办法4 CAN配置参考代码 1 问题描述 GD32的CAN1无法进入接收中断&#xff0c;收不到数据。 注&#xff1a;MCU使用的是GD32E50x&#xff0c;其他型号不确定是否一样&#xff0c;本文只以GD32E50x举例说…

【Docker】gitea的ssh容器直通

本文首发于 ❄️慕雪的寒舍 1.跟着文档走 gitea的安装比较简单&#xff0c;直接使用官方文档中的docker-compose文件即可。如果想实现ssh容器直通&#xff0c;需要对这个docker-compose文件做一定修改。 如果你还没有安装docker&#xff0c;参考本站教程 linux安装docker&…

QT-贪吃蛇小游戏

QT-贪吃蛇小游戏 一、演示效果二、核心代码三、下载链接 一、演示效果 二、核心代码 #include "Food.h" #include <QTime> #include <time.h> #include "Snake.h"Food::Food(int foodSize):foodSize(foodSize) {coordinate.x -1;coordinate.…

多线程(4)——单例模式、阻塞队列、线程池、定时器

1. 多线程案例 1.1 单例模式 单例模式能保证某个类在程序中只存在唯一一份实例&#xff0c;不会创建出多个实例&#xff08;这一点在很多场景上都需要&#xff0c;比如 JDBC 中的 DataSource 实例就只需要一个 tip&#xff1a;设计模式就是编写代码过程中的 “软性约束”&am…

系统稳定性建设的深度剖析与未来展望

一、系统稳定性的重要意义 系统稳定性是系统正常运行的关键&#xff0c;其缺失会导致严重后果&#xff0c;如经济损失、用户流失等。 以在线学习平台为例&#xff0c;如果系统频繁出现卡顿、掉线等问题&#xff0c;影响用户的学习体验&#xff0c;导致用户流失&#xff0c;平…

【HTML】从0开始构建HTML页面

1、HTML文档基本格式 1.1、!DOCTYPE:文档类型声明 1.2、html:根标签 1.3、head:头部标签 1.4、body:主体标签 2、头部相关标签 2.1、< title> < title>标签用于定义HTML页面的标题&#xff0c;即给网页取一个名字&#xff0c;必须位于< head>标签之内。 …

Programmatically add website content to OpenAI with C#

题意&#xff1a;使用 C# 以编程方式将网站内容添加到 OpenAI。 问题背景&#xff1a; Our goal is to have a ChatGPT answer questions about our websites content. 我们的目标是让 ChatGPT 回答关于我们网站内容的问题。 We are trying to integrate something similar t…

设计模式笔记01(java版)

文章目录 设计模式概述学习设计模式的必要性设计模式分类创建型模式结构型模式行为型模式 UML类图概述类图的作用类图表示法类的表示方式类与类之间关系的表示方式1&#xff0c;单向关联2&#xff0c;双向关联3&#xff0c;自关联聚合关系组合关系依赖关系继承关系实现关系 软件…

【hot100篇-python刷题记录】【买卖股票的最佳时机】

摆烂几天,又来了。 R5-贪心篇(不像) 贪心的常规思路是找到贪心切入点,例如最经典的算法是安排最多活动问题,需要以结束时间排序,然后遍历不冲突,计算最大数即可(每次都选择最早结束的活动)。 贪心算法的使用需要满足贪心特征。即局部最优解等于全局最优解。 对于本…

Docker 修改容器端口映射(以 Portainer 为例)

文章目录 背景解决第1步:找到容器id第2步:查找docker根目录第3步:停止docker服务第4步:修改容器的hostconfig.json配置文件第5步:启动docker服务第6步:验证参考背景 项目中有个服务也使用了9000端口,而Portainer的默认端口也是9000。结果可想而知,端口冲突,肯定有一个…