C++备忘录模式实践:轻松实现撤销与恢复功能
目录标题
- 引言(Introduction)
- 备忘录模式定义及核心概念(Memento Pattern Definition and Core Concepts)
- 备忘录模式的定义(Definition of Memento pattern)
- 备忘录模式的主要角色(Key roles in Memento pattern)
- 备忘录模式的UML图
- 备忘录模式的使用场景(When to Use Memento Pattern)
- 撤销操作(Undo functionality)
- 恢复操作(Redo functionality)
- 状态存储与恢复(State storage and restoration)
- 用C++实现备忘录模式(Implementing Memento Pattern in C++)
- 代码示例(Code example)
- 代码解析(Code explanation):
- 备忘录模式的优缺点(Pros and Cons of Memento Pattern)
- 备忘录模式的优点(Pros of Memento Pattern)
- 备忘录模式的缺点(Cons of Memento Pattern)
- 备忘录模式与其他设计模式的关联(Relationship with Other Design Patterns)
- 备忘录模式与命令模式(Memento pattern and Command pattern)
- 备忘录模式与状态模式(Memento pattern and State pattern)
- 实际案例:C++应用中的备忘录模式(Real-life Case: Memento Pattern in C++ Application)
- 案例描述(Case description):
- 案例实现(Case implementation):
- 总结(Conclusion)
- 备忘录模式的重要性(The importance of Memento pattern)
- 选择合适的设计模式(Choosing the right design pattern)
引言(Introduction)
备忘录模式(Memento Pattern)是一种行为型设计模式,它的主要目的是在不违反对象封装性的前提下,捕捉和保存对象的内部状态,以便将来可以将对象恢复到先前的状态。它通常用于实现撤销(Undo)和重做(Redo)操作,同时也适用于保存和恢复应用程序的状态。
备忘录模式通过在三个主要角色之间建立关系来实现这些功能:发起人(Originator)、备忘录(Memento)和管理者(Caretaker)。
- 发起人(Originator):负责创建一个备忘录,用于保存其当前状态,同时还负责从备忘录中恢复状态。
- 备忘录(Memento):存储发起人的内部状态,但不应该直接暴露给其他对象。备忘录应该保持不变,并且只能由发起人访问和修改。
- 管理者(Caretaker):负责管理和维护备忘录对象,但不应该修改或访问备忘录中存储的状态。管理者可以根据需要存储多个备忘录,并在需要时将发起人恢复到相应的状态。
备忘录模式的应用场景包括实现撤销和重做操作、状态存储与恢复等。使用备忘录模式可以简化撤销和重做操作的实现,同时保持代码的可读性和可维护性。
备忘录模式定义及核心概念(Memento Pattern Definition and Core Concepts)
备忘录模式的定义(Definition of Memento pattern)
备忘录模式(Memento Pattern)是一种行为型设计模式,它提供了一种在不破坏对象封装性的前提下捕捉和保存对象的内部状态,以便后续可以将对象恢复到先前的状态。备忘录模式通过将发起人(Originator)的内部状态存储在一个名为备忘录(Memento)的对象中,并由管理者(Caretaker)负责管理和维护备忘录,从而实现撤销和重做操作,以及状态存储与恢复等功能。
备忘录模式的主要角色(Key roles in Memento pattern)
备忘录模式的主要角色(Key roles in Memento pattern)
- 发起人(Originator): 发起人是一个具有内部状态的对象,负责创建备忘录以保存其当前状态,并从备忘录中恢复状态。发起人可以创建一个备忘录对象,用于存储其内部状态,同时也可以通过备忘录对象恢复到某个之前的状态。发起人不应该与管理者直接交互,而应该通过备忘录来实现状态的保存和恢复。
- 备忘录(Memento): 备忘录是一个用于存储发起人内部状态的对象,它应该保持对发起人状态的封装,不向其他对象暴露发起人的内部状态。备忘录应该保持不变,并且只能由发起人访问和修改。通常,备忘录类设计为嵌套类,以确保只有发起人能够访问和操作备忘录。
- 管理者(Caretaker): 管理者负责管理和维护备忘录对象,但不应该修改或访问备忘录中存储的状态。管理者可以根据需要存储多个备忘录,并在需要时将发起人恢复到相应的状态。管理者通常会为发起人提供保存和恢复状态的功能,如撤销(Undo)和重做(Redo)操作。
这三个角色之间的关系使得备忘录模式能够在不破坏对象封装性的前提下实现状态的保存和恢复。这样的设计提高了代码的可读性和可维护性,并降低了发起人与管理者之间的耦合度。
备忘录模式的UML图
备忘录模式的UML图包含以下三个类:
- Originator(发起人)
- Memento(备忘录)
- Caretaker(管理者)
下面是备忘录模式的UML图:
+----------------+ +------------+ +------------+
| Originator |<------>| Memento | | Caretaker |
+----------------+ +------------+ +------------+
| | | | | |
| +createMemento()| |+getState() | | +addMemento()|
| +restore(memento: Memento)| |+setState(state: State) | |+getMemento(index: int)|
| | | | | |
+----------------+ +------------+ +------------+
在这个UML图中:
- Originator(发起人)类具有
createMemento()
方法,用于创建一个备忘录对象以存储其内部状态;restore(memento: Memento)
方法用于通过备忘录对象恢复到先前的状态。 - Memento(备忘录)类具有
getState()
和setState(state: State)
方法,用于存储和获取发起人的内部状态。这两个方法通常只能被发起人访问和使用。 - Caretaker(管理者)类具有
addMemento()
方法,用于存储备忘录对象;getMemento(index: int)
方法用于根据索引获取备忘录对象,以便将发起人恢复到相应的状态。
这个UML图展示了备忘录模式的结构和关键组件。通过这种设计,备忘录模式可以实现在不破坏对象封装性的前提下保存和恢复对象的内部状态。
备忘录模式的使用场景(When to Use Memento Pattern)
撤销操作(Undo functionality)
在许多应用程序中,用户可能希望取消先前执行的操作,将应用程序恢复到以前的状态。例如,在文本编辑器中,用户可能希望撤销键入的字符或删除的文本。在这种情况下,备忘录模式是一种理想的解决方案,它允许在不违反对象封装性的前提下捕捉和保存对象的内部状态。
当使用备忘录模式实现撤销操作时,发起人(Originator)负责创建备忘录以保存其当前状态,并从备忘录中恢复状态。管理者(Caretaker)负责存储备忘录并提供撤销功能。当用户执行撤销操作时,管理者从备忘录中获取先前的状态,并将发起人恢复到该状态。
使用备忘录模式实现撤销操作的优势包括:
- 易于实现:备忘录模式提供了一种简单的方法来捕捉和存储对象的状态,从而简化了撤销操作的实现。
- 封装性:备忘录模式不会破坏对象的封装性,因为它将状态存储在备忘录对象中,而不是直接访问或修改发起人的内部状态。
- 可扩展性:备忘录模式可以轻松地扩展以支持重做操作和其他状态恢复功能。
恢复操作(Redo functionality)
恢复操作(Redo)是在应用程序中允许用户重做先前撤销的操作。这在很多场景中都是有用的,例如文本编辑器、绘图软件或游戏中。在这些情况下,备忘录模式同样可以作为实现重做功能的理想解决方案。
当使用备忘录模式实现重做操作时,管理者(Caretaker)负责存储备忘录并提供重做功能。在执行撤销操作后,管理者将保留一个指向撤销前的备忘录的引用。当用户执行重做操作时,管理者使用该引用将发起人(Originator)恢复到撤销前的状态。
使用备忘录模式实现重做操作的优势包括:
- 易于实现:与实现撤销操作类似,备忘录模式提供了一种简单的方法来捕捉和存储对象的状态,从而简化了重做操作的实现。
- 封装性:备忘录模式保持了对象的封装性,因为它将状态存储在备忘录对象中,而不是直接访问或修改发起人的内部状态。
- 可扩展性:备忘录模式可以轻松地扩展以支持多步撤销和重做操作,以及其他状态恢复功能。
状态存储与恢复(State storage and restoration)
在某些应用程序中,可能需要保存和恢复对象的状态。这种情况下,备忘录模式可以作为一种有效的解决方案。状态存储与恢复功能可以应用于多种场景,如游戏存档、软件设置恢复等。
使用备忘录模式实现状态存储与恢复的优势包括:
- 封装性:备忘录模式通过将状态保存在备忘录对象中,而不是直接访问或修改发起人的内部状态,从而保持了对象的封装性。
- 易于实现:备忘录模式提供了一种简单的方法来捕捉和存储对象的状态,从而简化了状态存储与恢复功能的实现。
- 可扩展性:备忘录模式可以轻松地扩展,以支持跨越多个状态变化的状态存储与恢复功能,同时也适用于不同类型的发起人对象。
当使用备忘录模式实现状态存储与恢复时,发起人(Originator)负责创建备忘录以保存其当前状态,并从备忘录中恢复状态。管理者(Caretaker)负责存储备忘录并提供保存和恢复状态的功能。在需要保存状态时,管理者通过发起人创建一个备忘录对象;在需要恢复状态时,管理者将发起人恢复到相应的备忘录状态。
用C++实现备忘录模式(Implementing Memento Pattern in C++)
代码示例(Code example)
#include <iostream>
#include <string>
#include <vector>class Memento {friend class Originator;private:std::string state;Memento(const std::string& state) : state(state) {}std::string getState() const {return state;}void setState(const std::string& newState) {state = newState;}
};class Originator {
public:Originator(const std::string& state) : state(state) {}Memento createMemento() {return Memento(state);}void restore(const Memento& memento) {state = memento.getState();}std::string getState() const {return state;}void setState(const std::string& newState) {state = newState;}private:std::string state;
};class Caretaker {
public:void addMemento(const Memento& memento) {mementos.push_back(memento);}Memento getMemento(size_t index) const {if (index < mementos.size()) {return mementos[index];}return Memento("");}private:std::vector<Memento> mementos;
};int main() {Originator originator("Initial State");Caretaker caretaker;caretaker.addMemento(originator.createMemento());originator.setState("State 1");caretaker.addMemento(originator.createMemento());originator.setState("State 2");caretaker.addMemento(originator.createMemento());// Restore state to "State 1"originator.restore(caretaker.getMemento(1));std::cout << "Restored state: " << originator.getState() << std::endl;return 0;
}
代码解析(Code explanation):
在这个代码示例中,我们实现了三个类:Memento
、Originator
和Caretaker
。
Memento
类用于存储发起人的内部状态。它具有私有的构造函数、getState()
和setState()
方法,这些方法只能由Originator
类访问。这样,我们确保了对象的封装性得以维护。Originator
类包含一个内部状态,并具有createMemento()
方法和restore()
方法。createMemento()
方法用于创建一个备忘录对象以保存当前状态;restore()
方法用于通过备忘录对象恢复到先前的状态。Caretaker
类负责存储和管理备忘录对象。它具有addMemento()
方法,用于添加备忘录对象;getMemento()
方法用于根据索引获取备忘录对象。
在 main()
函数中,我们创建了一个 Originator
对象,并修改了它的状态。随后,我们使用 Caretaker
对象来存储和恢复 Originator
的状态。通过运行这个程序,我们可以看到备忘录模式如何实现状态的保存和恢复,同时保持对象的封装性。
备忘录模式的优缺点(Pros and Cons of Memento Pattern)
备忘录模式的优点(Pros of Memento Pattern)
- 封装性:备忘录模式确保了发起人(Originator)对象的内部状态不会直接暴露给外部。状态的保存和恢复通过备忘录(Memento)对象进行,而不需要访问或修改发起人的内部状态。这样,备忘录模式可以保持对象的封装性。
- 易于实现:备忘录模式提供了一种简单且易于实现的方法来保存和恢复对象状态。通过将状态保存在备忘录对象中,我们可以实现撤销、重做等操作,而无需复杂的实现方式。
- 可扩展性:备忘录模式可以很容易地扩展以支持多种状态恢复功能,如多步撤销、重做操作等。此外,它还适用于不同类型的发起人对象,提供了一种通用的状态管理方法。
- 能够支持事务:备忘录模式能够支持事务,即一系列操作可以作为一个整体来执行。如果在执行事务过程中发生错误,可以利用备忘录模式将系统恢复到事务开始之前的状态。这使得应用程序更加健壮和可靠。
备忘录模式的缺点(Cons of Memento Pattern)
- 内存消耗:由于备忘录模式需要为每个保存的状态创建一个备忘录对象,这可能导致较高的内存消耗,尤其是在需要保存大量状态或频繁进行状态保存的场景中。
- 性能开销:当发起人(Originator)对象的状态较大或复杂时,创建备忘录对象和恢复状态的过程可能会导致性能开销。此外,管理者(Caretaker)需要维护备忘录对象的列表,这也可能在一定程度上影响性能。
- 维护难度:当发起人对象的内部状态发生更改时,可能需要相应地更新备忘录类。这可能会增加系统的维护难度和复杂性。
尽管备忘录模式存在这些缺点,但在需要实现状态保存和恢复的场景中,它仍然是一种有效且广泛使用的设计模式。在实际应用中,开发者需要根据具体需求权衡优缺点,以决定是否使用备忘录模式。
备忘录模式与其他设计模式的关联(Relationship with Other Design Patterns)
备忘录模式与命令模式(Memento pattern and Command pattern)
备忘录模式和命令模式之间有一定的关联,它们都可以用于实现撤销(Undo)和重做(Redo)功能。然而,两者在实现这些功能时的方法和重点有所不同。
- 实现方式:命令模式通过将操作封装成对象来实现撤销和重做功能。每个命令对象具有执行(execute)和撤销(undo)方法,用于执行操作或撤销操作。而备忘录模式通过保存和恢复对象的状态来实现撤销和重做功能。
- 状态保存:在命令模式中,可以在命令对象中保存足够的信息以便在需要时撤销操作。而在备忘录模式中,状态保存在备忘录对象中,而不是命令对象中。
- 封装性:备忘录模式保持了对象的封装性,因为它将状态存储在备忘录对象中,而不是直接访问或修改发起人的内部状态。而在命令模式中,封装性可能会受到一定程度的影响,因为命令对象可能需要访问和修改接收者对象的状态以执行和撤销操作。
- 适用场景:命令模式更适用于需要将操作封装为对象、实现宏命令(一组命令的组合)或者需要将命令放入队列中以便稍后执行的场景。而备忘录模式更适用于需要保存和恢复对象状态的场景,尤其是在需要保持对象封装性的情况下。
在实际应用中,备忘录模式和命令模式可以独立使用,也可以结合使用。例如,在实现一个文本编辑器时,可以使用命令模式来封装文本操作(如插入、删除等),同时使用备忘录模式来保存和恢复文本状态,实现撤销和重做功能。这样,我们可以充分利用两种设计模式的优势,实现一个更加灵活和高效的系统。
备忘录模式与状态模式(Memento pattern and State pattern)
备忘录模式和状态模式在一定程度上有关联,但它们的目的和实现方式有所不同。
- 目的:备忘录模式主要关注保存和恢复对象的内部状态,通常用于实现撤销(Undo)和重做(Redo)操作。而状态模式主要关注对象状态的变化以及根据状态改变对象的行为。状态模式通过将状态封装为独立的对象,并在运行时切换这些状态对象来改变对象的行为。
- 状态管理:在备忘录模式中,对象的状态保存在备忘录(Memento)对象中,而不直接暴露给外部。发起人(Originator)对象通过创建备忘录对象和恢复备忘录对象的状态来实现状态的保存和恢复。而在状态模式中,状态以独立的状态对象形式存在,这些状态对象定义了对象在特定状态下的行为。当对象的状态发生变化时,会切换到相应的状态对象。
- 封装性:备忘录模式保持了发起人对象的封装性,因为状态的保存和恢复通过备忘录对象进行,而不需要访问或修改发起人的内部状态。而在状态模式中,封装性体现在将状态相关的行为封装在各自的状态对象中,从而遵循单一职责原则。
- 适用场景:备忘录模式适用于需要保存和恢复对象状态的场景,尤其是在需要保持对象封装性的情况下。而状态模式适用于对象状态的变化会导致对象行为发生变化的场景,以便在运行时灵活地切换行为。
尽管备忘录模式和状态模式有一定的关联,但它们解决的问题和实现方式有所不同。在实际开发中,根据具体需求和场景选择合适的设计模式是至关重要的。有时,这两种模式甚至可以结合使用,以实现更加灵活和高效的系统。
实际案例:C++应用中的备忘录模式(Real-life Case: Memento Pattern in C++ Application)
案例描述(Case description):
假设我们正在开发一个简单的文本编辑器,允许用户对文本进行插入、删除、修改等操作。为了提供更好的用户体验,我们希望添加撤销(Undo)和重做(Redo)功能,以便用户可以撤销或重做他们的操作。在这个案例中,我们可以使用备忘录模式来保存和恢复文本编辑器的状态。
案例实现(Case implementation):
首先,我们需要定义三个类:Editor
(发起人),EditorMemento
(备忘录),和EditorCaretaker
(管理者)。
#include <iostream>
#include <string>
#include <stack>class EditorMemento {
public:EditorMemento(const std::string& content) : content_(content) {}std::string getContent() const { return content_; }private:std::string content_;
};class Editor {
public:void type(const std::string& words) { content_ += words; }std::string getContent() const { return content_; }EditorMemento save() const { return EditorMemento(content_); }void restore(const EditorMemento& memento) { content_ = memento.getContent(); }private:std::string content_;
};class EditorCaretaker {
public:void saveState(const EditorMemento& memento) { history_.push(memento); }EditorMemento undo() {if (history_.empty()) {throw std::runtime_error("No states to undo.");}EditorMemento memento = history_.top();history_.pop();return memento;}private:std::stack<EditorMemento> history_;
};
接下来,我们可以使用Editor
类和EditorCaretaker
类来实现撤销和重做功能:
int main() {Editor editor;EditorCaretaker caretaker;editor.type("This is a sample text. ");caretaker.saveState(editor.save());editor.type("Adding more text. ");caretaker.saveState(editor.save());editor.type("And even more text. ");std::cout << "Current content: " << editor.getContent() << std::endl;// Undo the last two operations.editor.restore(caretaker.undo());editor.restore(caretaker.undo());std::cout << "Content after undo: " << editor.getContent() << std::endl;return 0;
}
在这个例子中,我们首先创建了一个Editor
对象和一个EditorCaretaker
对象。在进行文本操作之后,我们使用save()
方法创建一个备忘录对象,并将其传递给EditorCaretaker
对象的saveState()
方法以保存状态。当需要撤销操作时,我们可以通过调用EditorCaretaker
对象的undo()
方法来获取先前保存的备忘录对象,并使用restore()
方法将编辑器状态恢复到该备忘录对象所保存的状态。
这个实际案例展示了如何在C++应用中使用备忘录模式来实现撤销和重做功能。通过使用备忘录模式,我们可以轻松地保存和恢复文本编辑器的状态,同时保持了对象的封装性。这个设计模式为实现复杂操作提供了强大的支持,同时提高了代码的可维护性和可扩展性。
在实际开发过程中,备忘录模式可以广泛应用于各种场景,如游戏存档、版本控制系统等。通过合理地运用备忘录模式,我们可以实现更加高效和灵活的系统。
此外,还可以将备忘录模式与其他设计模式结合使用,以实现更丰富的功能。例如,在实现文本编辑器的撤销和重做功能时,我们可以将备忘录模式与命令模式结合使用。这样,我们可以将文本操作封装为命令对象,然后使用备忘录模式来保存和恢复这些命令对象的状态。这种组合将充分利用两种设计模式的优势,实现一个功能强大、易于维护和扩展的系统。
总之,备忘录模式为处理对象状态的保存和恢复提供了一个有效的解决方案。在实际开发中,我们需要根据具体需求和场景选择合适的设计模式,以提高代码质量和实现更加高效的系统。
总结(Conclusion)
备忘录模式的重要性(The importance of Memento pattern)
备忘录模式是一种行为型设计模式,其主要目的是在不破坏对象封装性的前提下,捕获并保存对象的内部状态,以便后续可以将对象恢复到先前的状态。备忘录模式在实际应用中具有广泛的应用场景,例如撤销操作、重做操作、游戏存档、版本控制系统等。通过使用备忘录模式,我们可以提高代码的可维护性、可扩展性以及易用性,从而构建出高质量、高性能的软件系统。
选择合适的设计模式(Choosing the right design pattern)
在实际开发过程中,选择合适的设计模式是至关重要的。每种设计模式都有其特定的应用场景和优缺点,因此我们需要根据项目的需求和场景来选择适合的设计模式。在决定是否使用备忘录模式时,我们需要考虑以下几点:
- 是否需要保存和恢复对象的状态?
- 是否希望在不破坏对象封装性的前提下实现状态的保存和恢复?
- 是否需要支持撤销和重做等操作?
如果以上问题的答案都是肯定的,那么备忘录模式很可能是一个合适的选择。同时,我们还需要关注备忘录模式与其他设计模式之间的关系,以便在需要时能够灵活地组合和应用这些设计模式,从而实现更加高效、灵活和可维护的系统。
相关文章:
C++备忘录模式实践:轻松实现撤销与恢复功能
目录标题 引言(Introduction)备忘录模式定义及核心概念(Memento Pattern Definition and Core Concepts)备忘录模式的定义(Definition of Memento pattern)备忘录模式的主要角色(Key roles in M…...

如何选择CDN加速平台?
现如今全球CDN市场规模逐年攀升,在2017年全球CDN市场规模约为75亿美元,到2021年增长到200亿美元左右。我国CDN行业同样保持高速发展,自2017年的135亿元增长到2022年的300亿元左右。但是国内的CDN市场规模仅为全球市场的15%-20%,海外CDN市场空间巨大。 接…...

其实苹果知道自己离不开中国制造,因此悄悄给自己留了后路
苹果在加速离开中国,不过从苹果的做法却又可以看到它其实很清醒地认识到无法离开中国制造,因此它在力推印度制造的时候,其实并没拼尽全力,深刻认识到印度制造和印度市场与中国的差距。 一、印度制造和印度市场与中国的差距 2022年…...

必用WhatsApp营销的4个理由
WhatsApp是世界上最受欢迎的消息传递应用程序。每天有1万新用户加入WhatsApp。各种规模的公司都利用该平台与世界各地的客户进行有效的沟通,这要归功于其广泛的覆盖范围、用户友好的设计和安全的端到端加密。因此,WhatsApp聊天机器人迅速普及。 1.为您的…...
Python从入门到精通9天(异常的处理)
异常处理 异常处理语句多个异常raise关键字常见的异常类型自定义异常 异常处理语句 在了解异常处理之前,我们先对它的语句进行说明,如下: try:表示测试代码块以查找错误 except:表示处理错误 finally:表…...

微服务学习——Docker
初识Docker 项目部署的问题 大型项目组件较多,运行环境也较为复杂,部署时会碰到一些问题: 依赖关系复杂,容易出现兼容性问题开发、测试、生产环境有差异 Docker Docker如何解决依赖的兼容问题的? 将应用的Libs(函数库)、 Deps…...

QMS-云质说质量 - 5 解决中小企业质量问题的钥匙在哪里?
云质QMS原创 转载请注明来源 作者:王洪石 引言 一个小小的质量问题可能引发蝴蝶效应 日常生活中,我们每天都会遇到各种各样的问题,并随着它们喜怒哀乐。企业也不例外,即使有很好的管理体系以及非常高素质的员工,一些错…...

基于Java+Spring+vue+element社区疫情服务平台设计和实现
基于JavaSpringvueelement社区疫情服务平台设计和实现 博主介绍:5年java开发经验,专注Java开发、定制、远程、指导等,csdn特邀作者、专注于Java技术领域 作者主页 超级帅帅吴 Java项目精品实战案例《500套》 欢迎点赞 收藏 ⭐留言 文末获取源码联系方式 …...

实战项目:手把手带你实现一个高并发内存池
项目介绍 1.这个项目做的是什么? 当前项目是实现一个高并发的内存池,他的原型是google的一个开源项目tcmalloc,tcmalloc全称Thread-Caching Malloc,即线程缓存的malloc,实现了高效的多线程内存管理,用于替…...

原理这就是索引下推呀
前些天发现了一个巨牛的人工智能学习网站,通俗易懂,风趣幽默,忍不住分享一下给大家。点击跳转到网站。 索引下推是之前面试的时候遇到的一个面试题,当时没有答上来,今天来学习一下。 介绍索引下推之前先看一下MySQL基…...
个人通讯录(二)
个人通讯录(二) 需求: 通讯录(phone)用来保存若干个联系人的信息,且可以按照联系人姓名的拼音升序排序。要求通讯录提供一下功能: 1.添加联系人信息 2.删除指定联系人信息 3.修改指定联系人…...
DockerK8S常见面试知识
Docker docker的工作原理 docker是一个client-server结构的系统,docker守护进程运行在宿主机上,守护进程从客户端接受命令并管理运行在主机上的容器,容器是一个运行时环境,这就是我们说的集装箱 docker组成部分 1、docker cli…...
tcpdump arping nsenter
tcpdump 参数说明 tcpdump 是一款常用的网络抓包工具,它可以捕获网络数据包并进行分析。tcpdump 的参数非常多,下面是一些常用的参数说明: -i:指定要监听的网络接口,如 -i eth0。 any-n:禁用地址解析&…...
Python - 简单快速回忆基础语法
Python 是一种高级编程语言,易学易用 以下是 Python 基础语法的概述: 注释 Python 使用 # 符号来注释代码行。代码行 # 后的所有内容都将被认为是注释,不会被解释器执行,只是对代码的注释说明 # 这是一条注释 print("Hel…...

蓝牙耳机接打电话哪个比较好?接打电话最好的蓝牙耳机
技术已经发展到如此程度,耳机可以淹没嘈杂环境中不断出现的杂音,同时还能让我们在通话、音乐和娱乐方面保持清晰,既然如此,我们就来整理一下2023年适合通话和娱乐的无线耳机清单。 一、南卡小音舱Lite2蓝牙耳机 参考价格&#x…...

DeepSORT中的卡尔曼滤波
本文是看了DeepSORT方法视频之后,关于其中使用的卡尔曼滤波的理解 DeepSORT视频链接 首先贴几个比较好的,与本文由有关的几个帖子 图说卡尔曼滤波,一份通俗易懂的教程 卡尔曼滤波(Kalman Filter)原理与公式推导 卡尔…...

【Linux网络服务】SSH远程访问及控制
一、openssh服务器 1.1ssh协议 SSH(Secure Shell)是一种安全通道协议,主要用来实现字符界面的远程登录、远程 复制等功能; SSH 协议对通信双方的数据传输进行了加密处理,其中包括用户登录时输入的用户口令࿱…...

AutoGPT的出现,会让程序员失业吗?
最近,一个叫AutoGPT的模型火了,在GitHub上线数周Star数就直线飙升。截至目前,AutoGPT的Star数已经达到87k,马上接近90k,超过了PyTorch的65k。 根据AutoGPT的命名,就可以发现其神奇之处在于“auto”&#x…...

微信小程序php+vue 校园租房指南房屋租赁系统
本着诚信的原则,平台必须要掌握出租方必要的真实可信的信息,这样就可以防止欺诈事件的发生,事后也可以联系找到出租方。并且租金等各方面规范标准化,在这易租房诚信可信的平台让承租方与出租方充分有效对接,既方便了承…...

水果FL Studio21最新中文完整版下载更新及内容介绍
简单总结一下,本次小版本更新最重要的内容,我个人认为是对于M1芯片的适配。其余的比如EQ2,3x这些我们很熟悉的插件虽说也有更新,但是估计并没有特别大的改动。我个人的话会先放一段时间,等下次有其他更让我感兴趣的内容…...
Leetcode 3576. Transform Array to All Equal Elements
Leetcode 3576. Transform Array to All Equal Elements 1. 解题思路2. 代码实现 题目链接:3576. Transform Array to All Equal Elements 1. 解题思路 这一题思路上就是分别考察一下是否能将其转化为全1或者全-1数组即可。 至于每一种情况是否可以达到…...

ESP32读取DHT11温湿度数据
芯片:ESP32 环境:Arduino 一、安装DHT11传感器库 红框的库,别安装错了 二、代码 注意,DATA口要连接在D15上 #include "DHT.h" // 包含DHT库#define DHTPIN 15 // 定义DHT11数据引脚连接到ESP32的GPIO15 #define D…...

剑指offer20_链表中环的入口节点
链表中环的入口节点 给定一个链表,若其中包含环,则输出环的入口节点。 若其中不包含环,则输出null。 数据范围 节点 val 值取值范围 [ 1 , 1000 ] [1,1000] [1,1000]。 节点 val 值各不相同。 链表长度 [ 0 , 500 ] [0,500] [0,500]。 …...

DIY|Mac 搭建 ESP-IDF 开发环境及编译小智 AI
前一阵子在百度 AI 开发者大会上,看到基于小智 AI DIY 玩具的演示,感觉有点意思,想着自己也来试试。 如果只是想烧录现成的固件,乐鑫官方除了提供了 Windows 版本的 Flash 下载工具 之外,还提供了基于网页版的 ESP LA…...

html-<abbr> 缩写或首字母缩略词
定义与作用 <abbr> 标签用于表示缩写或首字母缩略词,它可以帮助用户更好地理解缩写的含义,尤其是对于那些不熟悉该缩写的用户。 title 属性的内容提供了缩写的详细说明。当用户将鼠标悬停在缩写上时,会显示一个提示框。 示例&#x…...
Go 语言并发编程基础:无缓冲与有缓冲通道
在上一章节中,我们了解了 Channel 的基本用法。本章将重点分析 Go 中通道的两种类型 —— 无缓冲通道与有缓冲通道,它们在并发编程中各具特点和应用场景。 一、通道的基本分类 类型定义形式特点无缓冲通道make(chan T)发送和接收都必须准备好࿰…...

【C++进阶篇】智能指针
C内存管理终极指南:智能指针从入门到源码剖析 一. 智能指针1.1 auto_ptr1.2 unique_ptr1.3 shared_ptr1.4 make_shared 二. 原理三. shared_ptr循环引用问题三. 线程安全问题四. 内存泄漏4.1 什么是内存泄漏4.2 危害4.3 避免内存泄漏 五. 最后 一. 智能指针 智能指…...
站群服务器的应用场景都有哪些?
站群服务器主要是为了多个网站的托管和管理所设计的,可以通过集中管理和高效资源的分配,来支持多个独立的网站同时运行,让每一个网站都可以分配到独立的IP地址,避免出现IP关联的风险,用户还可以通过控制面板进行管理功…...

脑机新手指南(七):OpenBCI_GUI:从环境搭建到数据可视化(上)
一、OpenBCI_GUI 项目概述 (一)项目背景与目标 OpenBCI 是一个开源的脑电信号采集硬件平台,其配套的 OpenBCI_GUI 则是专为该硬件设计的图形化界面工具。对于研究人员、开发者和学生而言,首次接触 OpenBCI 设备时,往…...
从面试角度回答Android中ContentProvider启动原理
Android中ContentProvider原理的面试角度解析,分为已启动和未启动两种场景: 一、ContentProvider已启动的情况 1. 核心流程 触发条件:当其他组件(如Activity、Service)通过ContentR…...