您的位置:首页 > 新闻 > 会展 > 网站建设的目的_公众号免费素材网站_网页制作代码模板_网站seo分析案例

网站建设的目的_公众号免费素材网站_网页制作代码模板_网站seo分析案例

2024/12/26 1:13:52 来源:https://blog.csdn.net/joshua0137/article/details/144702553  浏览:    关键词:网站建设的目的_公众号免费素材网站_网页制作代码模板_网站seo分析案例
网站建设的目的_公众号免费素材网站_网页制作代码模板_网站seo分析案例

享元(Flyweight)模式的动机与意图

动机

享元模式的主要动机是通过共享对象来减少内存使用,从而提高系统的性能。在某些情况下,系统中可能有大量细粒度的对象,这些对象具有共同的部分状态,而这些状态可以共享。如果不进行共享,大量对象会占用大量的内存资源,特别是在对象的数量非常大的时候。享元模式通过共享这些对象的共有部分状态,使得系统只需要保存一份共有的状态,从而显著减少内存占用。

意图

享元模式的意图是通过共享技术来减少内存使用,并提高对象的创建和管理效率。具体来说,享元模式将一个对象的内部状态(可以共享的)和外部状态(不能共享的)分开,使得一个对象可以被多次共享,而每次使用时只需传递外部状态给对象。

适用场合

享元模式适用于以下场合:

  1. 对象数量庞大

    • 当一个应用程序中需要创建大量的对象,而这些对象占用大量内存时,可以考虑使用享元模式。通过共享这些对象的共有部分状态,可以显著减少内存占用。
  2. 对象状态可以分离

    • 对象的状态可以被分为内部状态和外部状态,其中内部状态是可以共享的,而外部状态是随上下文变化的。享元模式通过共享内部状态,同时在使用时传递外部状态,来实现对象的高效管理。
  3. 对象的大多数状态可以被外部化

    • 如果一个对象的大多数状态可以被外部化(即不保存在对象内部),并且这些状态可以在使用对象时传入,那么这个对象就适合使用享元模式。
  4. 需要缓存对象

    • 当需要缓存对象以提高访问效率时,可以通过享元模式来实现对象的共享和缓存,从而提高系统的性能。

具体示例

假设我们正在开发一个文本编辑器,需要在文档中显示大量的字符。每个字符对象都包含字体、颜色、大小等属性,如果不进行共享,每个字符的这些属性将占用大量的内存。通过享元模式,我们可以共享字符的字体、颜色和大小等共有部分状态,而每个字符的外部状态(如位置)则在使用时传递给对象。

字符类(内部状态)
#include <iostream>
#include <map>
#include <string>class Character {
private:char _value;
public:Character(char value) : _value(value) {}void display(const std::string& font, const std::string& color, int size) {std::cout << "显示字符: " << _value << ",字体: " << font << ",颜色: " << color << ",大小: " << size << std::endl;}
};class CharacterFactory {
private:std::map<char, std::shared_ptr<Character>> _characters;
public:std::shared_ptr<Character> getCharacter(char value) {if (_characters.find(value) == _characters.end()) {std::shared_ptr<Character> newChar = std::make_shared<Character>(value);_characters[value] = newChar;return newChar;} else {return _characters[value];}}
};

文档类(外部状态)
class Document {
private:std::vector<std::shared_ptr<Character>> _characters;std::string _font;std::string _color;int _size;
public:Document(const std::string& font, const std::string& color, int size) : _font(font), _color(color), _size(size) {}void addCharacter(char value, CharacterFactory& factory) {std::shared_ptr<Character> character = factory.getCharacter(value);_characters.push_back(character);}void display() {for (auto& character : _characters) {character->display(_font, _color, _size);}}
};

客户端代码
int main() {CharacterFactory factory;Document doc1("Arial", "Red", 12);doc1.addCharacter('A', factory);doc1.addCharacter('B', factory);doc1.addCharacter('C', factory);Document doc2("Times New Roman", "Blue", 14);doc2.addCharacter('A', factory);doc2.addCharacter('B', factory);doc2.addCharacter('D', factory);doc1.display();doc2.display();return 0;
}

代码解释

  1. Character 类

    • 代表一个字符对象,包含字符的值 _value
    • display 方法用于显示字符,同时接受字体、颜色和大小等外部状态作为参数。
  2. CharacterFactory 类

    • 用于创建和管理字符对象的工厂类。
    • 通过 getCharacter 方法,工厂类可以返回一个已存在的字符对象(共享对象),或者创建一个新的字符对象并加入到缓存中。
  3. Document 类

    • 代表一个文档,包含字符的集合 _characters 以及字体、颜色和大小等外部状态。
    • addCharacter 方法用于向文档中添加字符,通过 CharacterFactory 获取字符对象。
    • display 方法用于显示文档中的所有字符,同时传递字体、颜色和大小等外部状态给字符对象。
  4. 客户端代码

    • 创建 CharacterFactory 对象。
    • 创建两个文档对象 doc1 和 doc2,并分别为它们添加字符。
    • 显示两个文档中的字符,每个字符对象的内部状态(值)是共享的,而外部状态(字体、颜色、大小)是在使用时传递的。

总结

享元模式的主要动机是通过共享对象来减少内存使用,提高系统的性能。其适用场合包括:

  • 对象数量庞大:系统中存在大量细粒度的对象,这些对象占用大量内存。
  • 对象状态可以分离:对象的状态可以被分为内部状态和外部状态,其中内部状态是可以共享的。
  • 对象的大多数状态可以被外部化:对象的大多数状态可以不在对象内部保存,而是在使用对象时传入。
  • 需要缓存对象:通过缓存对象来提高访问效率。

通过享元模式,可以有效地管理和共享对象的共有状态,从而减少内存占用,提高系统性能。希望这些解释能帮助你更好地理解享元模式的动机、意图及其适用场合。

享元模式的 UML 类图

享元模式的 UML 类图如下所示:

+------------------------------+          +-----------------------------+
|         FlyweightFactory     |          |        Flyweight             |
|------------------------------|          |-----------------------------|
| +getInstance(key: String):   |          | +intrinsicState: String      |
|   Flyweight                   |          | +operation(extrinsicState:  |
|                               |          |   String): void             |
| +flyweights: Map<String,       |          |                             |
|   Flyweight>                  |          +-----------------------------+
| +getInstance(key: String):     |          |          +-----------------+
|   Flyweight                    |          |          | ConcreteFlyweight |
| +addFlyweight(key: String,     |          |          |------------------|
|   flyweight: Flyweight): void  |          |          | +intrinsicState: String|
+------------------------------+          |          | +operation(extrinsicState: ||          |   String): void            |+-----------------------------+         |+---------+

UML 类图解释

  1. FlyweightFactory

    • 职责:负责创建和管理享元对象。
    • 方法
      • getInstance(key: String): Flyweight:根据给定的键返回一个享元对象。如果享元对象已经存在于缓存中,则返回缓存中的对象;否则,创建一个新的享元对象并将其加入到缓存中,然后返回。
      • addFlyweight(key: String, flyweight: Flyweight): void:将新的享元对象添加到缓存中。
    • 属性
      • flyweights: Map<String, Flyweight>:存储享元对象的缓存,键通常是一个唯一标识符,用于区分不同的享元对象。
  2. Flyweight

    • 职责:定义享元对象的接口,该接口可以接受外部状态。
    • 方法
      • operation(extrinsicState: String): void:操作方法,接受外部状态作为参数。外部状态是随上下文变化的,而内部状态是共享的。
    • 属性
      • intrinsicState: String:内部状态,是可以共享的,通常在创建时设置,并且在对象的生命周期中保持不变。
  3. ConcreteFlyweight

    • 职责:实现 Flyweight 接口,定义具体的享元对象。
    • 方法
      • operation(extrinsicState: String): void:具体的实现,使用外部状态和内部状态来完成操作。
    • 属性
      • intrinsicState: String:共享的内部状态。 

享元模式的优缺点

优点
  • 减少内存占用:通过共享对象的内部状态,减少内存使用,提高系统性能。
  • 提高创建和管理效率:享元工厂可以缓存已经创建的享元对象,减少重复创建对象的开销。
  • 模块化设计:享元模式将对象的状态分离为内部状态和外部状态,使得系统的模块化设计更加清晰。
缺点
  • 增加系统复杂性:引入享元工厂和享元对象会增加系统的复杂性,需要管理内部状态和外部状态的分离。
  • 需要外部状态的传递:每次使用享元对象时,都需要传递外部状态,这可能会增加调用的复杂性。

通过享元模式,可以有效地管理和共享对象的共有状态,从而减少内存占用,提高系统的性能。希望这些解释能帮助你更好地理解享元模式的 UML 类图及其具体实现。

享元模式在C++池化技术中的应用

享元模式在池化技术中非常有用,特别是在需要频繁创建和销毁大量相似对象的场景中。 pooling(池化技术)通过预先创建一组对象并重复使用这些对象,来减少对象创建的开销和内存的频繁分配与释放。享元模式可以进一步优化池化技术,通过共享对象的内部状态来减少内存使用。

示例:GUI资源池中的享元模式

假设我们正在开发一个GUI应用程序,需要创建大量的按钮(Button)对象。每个按钮对象都有相同的背景图片,但按钮的文本内容和位置是不同的。我们可以使用享元模式来共享按钮的背景图片,从而减少内存占用。

1. 定义享元接口
#include <iostream>
#include <string>
#include <map>
#include <memory>class ButtonFlyweight {
public:virtual void draw(const std::string& text, int x, int y) const = 0;virtual ~ButtonFlyweight() {}
};

2. 定义具体享元
class ConcreteButtonFlyweight : public ButtonFlyweight {
private:std::string _backgroundImage; // 共享的内部状态
public:ConcreteButtonFlyweight(const std::string& backgroundImage) : _backgroundImage(backgroundImage) {}void draw(const std::string& text, int x, int y) const override {std::cout << "绘制按钮: " << text << ",位置: (" << x << ", " << y << "), 背景图片: " << _backgroundImage << std::endl;}
};

3. 定义享元工厂
class ButtonFlyweightFactory {
private:std::map<std::string, std::shared_ptr<ButtonFlyweight>> _flyweights;
public:std::shared_ptr<ButtonFlyweight> getButton(const std::string& backgroundImage) {if (_flyweights.find(backgroundImage) == _flyweights.end()) {std::shared_ptr<ButtonFlyweight> newButton = std::make_shared<ConcreteButtonFlyweight>(backgroundImage);_flyweights[backgroundImage] = newButton;}return _flyweights[backgroundImage];}
};

4. 定义GUI组件(使用享元)
class GUIComponent {
private:std::shared_ptr<ButtonFlyweight> _button;std::string _text;int _x;int _y;
public:GUIComponent(const std::string& text, int x, int y, ButtonFlyweightFactory& factory, const std::string& backgroundImage) :_text(text), _x(x), _y(y), _button(factory.getButton(backgroundImage)) {}void draw() const {_button->draw(_text, _x, _y);}
};

5. 客户端代码
int main() {ButtonFlyweightFactory buttonFactory;GUIComponent button1("Button 1", 10, 20, buttonFactory, "bg1.png");GUIComponent button2("Button 2", 30, 40, buttonFactory, "bg1.png");GUIComponent button3("Button 3", 50, 60, buttonFactory, "bg2.png");button1.draw();button2.draw();button3.draw();return 0;
}

代码解释

  1. ButtonFlyweight 接口

    • 定义了 draw 方法,该方法接受按钮的文本内容和位置(外部状态)作为参数。
  2. ConcreteButtonFlyweight 类

    • 实现了 ButtonFlyweight 接口,具体的 draw 方法使用传递进来的外部状态(按钮的文本内容和位置)和内部状态(背景图片)来绘制按钮。
  3. ButtonFlyweightFactory 类

    • 负责创建和管理 ButtonFlyweight 对象。
    • getButton 方法根据给定的背景图片返回一个享元对象。如果享元对象已经存在于缓存中,则返回缓存中的对象;否则,创建一个新的享元对象并将其加入到缓存中,然后返回。
    • _flyweights 属性是一个 map,用于存储享元对象,键是背景图片的路径。
  4. GUIComponent 类

    • 代表一个GUI组件,包含按钮的文本内容、位置等外部状态。
    • GUIComponent 构造函数接受按钮的文本内容、位置、享元工厂和背景图片路径作为参数,通过享元工厂获取享元对象。
    • draw 方法用于绘制按钮,调用享元对象的 draw 方法,传递按钮的文本内容和位置作为外部状态。
  5. 客户端代码

    • 创建 ButtonFlyweightFactory 对象。
    • 创建多个 GUIComponent 对象,每个对象使用相同的背景图片时,享元工厂会返回同一个享元对象。
    • 调用 draw 方法绘制按钮,每个按钮对象的内部状态(背景图片)是共享的,而外部状态(文本内容和位置)是在使用时传递的。

享元模式在GUI资源池中的优势

  1. 减少内存占用

    • 通过共享按钮的背景图片,可以显著减少内存使用。如果每个按钮都具有相同的背景图片,但不共享,那么每个按钮都会占用额外的内存来存储背景图片数据。
  2. 提高创建和管理效率

    • 享元工厂可以缓存已经创建的享元对象,减少重复创建对象的开销。这对于频繁创建和销毁按钮对象的场景非常有用。
  3. 模块化设计

    • 将按钮的内部状态(背景图片)和外部状态(文本内容和位置)分离,使得系统的模块化设计更加清晰。这有助于提高代码的可维护性和可扩展性。

进一步优化

在实际应用中,可以进一步优化享元模式,例如:

  • 使用智能指针:使用 std::shared_ptr 来管理享元对象的生命周期,确保对象在不再需要时被自动释放。
  • 多线程安全:如果应用是多线程的,可以在享元工厂中使用互斥锁(std::mutex)来确保线程安全。
  • 外部状态的封装:将外部状态封装在一个结构体或类中,然后传递给享元对象,以提高代码的可读性和可维护性。

通过这些优化,可以进一步提高享元模式在池化技术中的应用效果。希望这些解释和示例代码能帮助你更好地理解享元模式在C++池化技术中的应用。

 

结合 Composite 模式和 Flyweight 模式实现文档编辑器中的文本分层结构

在文档编辑器中,文本通常可以有层次结构,比如段落、行和字符等。我们可以使用 Composite 模式 来管理这种层次结构,而 Flyweight 模式 可以用来共享文本样式的内部状态,从而减少内存占用。为了进一步优化,我们还可以使用 有向无环图(DAG) 来实现 Flyweight 模式,使得多个对象可以共享复杂的内部状态。

示例代码

1. 定义享元接口
#include <iostream>
#include <string>
#include <map>
#include <memory>
#include <vector>class TextStyle {
public:virtual void render(char character) const = 0;virtual ~TextStyle() {}
};

2. 定义具体享元
class ConcreteTextStyle : public TextStyle {
private:std::string _font;std::string _color;int _size;
public:ConcreteTextStyle(const std::string& font, const std::string& color, int size) : _font(font), _color(color), _size(size) {}void render(char character) const override {std::cout << "绘制字符: " << character << ",字体: " << _font << ",颜色: " << _color << ",大小: " << _size << std::endl;}
};

3. 定义享元工厂
class TextStyleFactory {
private:std::map<std::string, std::shared_ptr<TextStyle>> _styles;
public:std::shared_ptr<TextStyle> getTextStyle(const std::string& font, const std::string& color, int size) {std::string key = font + "," + color + "," + std::to_string(size);if (_styles.find(key) == _styles.end()) {std::shared_ptr<TextStyle> newStyle = std::make_shared<ConcreteTextStyle>(font, color, size);_styles[key] = newStyle;}return _styles[key];}
};

4. 定义 Composite 模式中的组件接口
class TextComponent {
public:virtual void display() const = 0;virtual ~TextComponent() {}
};

5. 定义叶子节点(字符)
class TextCharacter : public TextComponent {
private:char _character;std::shared_ptr<TextStyle> _style;
public:TextCharacter(char character, const std::shared_ptr<TextStyle>& style) : _character(character), _style(style) {}void display() const override {_style->render(_character);}
};

6. 定义组合节点(段落)
class Paragraph : public TextComponent {
private:std::vector<std::shared_ptr<TextComponent>> _children;
public:void addChild(const std::shared_ptr<TextComponent>& child) {_children.push_back(child);}void display() const override {std::cout << "段落:" << std::endl;for (const auto& child : _children) {child->display();}}
};

7. 定义组合节点(行)
class Line : public TextComponent {
private:std::vector<std::shared_ptr<TextComponent>> _children;
public:void addChild(const std::shared_ptr<TextComponent>& child) {_children.push_back(child);}void display() const override {std::cout << "行:" << std::endl;for (const auto& child : _children) {child->display();}}
};

8. 客户端代码
int main() {TextStyleFactory styleFactory;// 创建文本样式std::shared_ptr<TextStyle> style1 = styleFactory.getTextStyle("Arial", "Red", 12);std::shared_ptr<TextStyle> style2 = styleFactory.getTextStyle("Times New Roman", "Blue", 14);// 创建字符std::shared_ptr<TextComponent> charA = std::make_shared<TextCharacter>('A', style1);std::shared_ptr<TextComponent> charB = std::make_shared<TextCharacter>('B', style1);std::shared_ptr<TextComponent> charC = std::make_shared<TextCharacter>('C', style1);std::shared_ptr<TextComponent> charD = std::make_shared<TextCharacter>('D', style2);std::shared_ptr<TextComponent> charE = std::make_shared<TextCharacter>('E', style2);// 创建行std::shared_ptr<TextComponent> line1 = std::make_shared<Line>();line1->addChild(charA);line1->addChild(charB);line1->addChild(charC);std::shared_ptr<TextComponent> line2 = std::make_shared<Line>();line2->addChild(charD);line2->addChild(charE);// 创建段落std::shared_ptr<TextComponent> paragraph = std::make_shared<Paragraph>();paragraph->addChild(line1);paragraph->addChild(line2);// 显示文档paragraph->display();return 0;
}

代码解释

  1. TextStyle 接口

    • 定义了一个 render 方法,该方法接受一个字符作为参数,并负责绘制该字符时使用特定的文本样式。
  2. ConcreteTextStyle 类

    • 实现了 TextStyle 接口,具体的 render 方法使用传递进来的字符和内部状态(字体、颜色、大小)来绘制字符。
  3. TextStyleFactory 类

    • 负责创建和管理 TextStyle 对象。
    • getTextStyle 方法根据给定的字体、颜色和大小生成一个唯一的键,并根据该键返回一个享元对象。如果享元对象已经存在于缓存中,则返回缓存中的对象;否则,创建一个新的享元对象并将其加入到缓存中,然后返回。
    • _styles 属性是一个 map,用于存储享元对象,键是字体、颜色和大小的组合字符串。
  4. TextComponent 接口

    • 定义了一个 display 方法,该方法用于显示文本组件。
  5. TextCharacter 类

    • 代表文档中的单个字符,继承自 TextComponent 接口。
    • display 方法调用享元对象的 render 方法来绘制字符。
  6. Line 类

    • 代表文档中的一行,继承自 TextComponent 接口。
    • addChild 方法用于向行中添加字符或其他文本组件。
    • display 方法遍历并显示所有子组件。
  7. Paragraph 类

    • 代表文档中的段落,继承自 TextComponent 接口。
    • addChild 方法用于向段落中添加行或其他文本组件。
    • display 方法遍历并显示所有子组件。
  8. 客户端代码

    • 创建 TextStyleFactory 对象。
    • 创建多个 ConcreteTextStyle 对象,并通过享元工厂获取它们。
    • 创建多个字符对象 TextCharacter,并指定其样式。
    • 创建行对象 Line,并向其中添加字符。
    • 创建段落对象 Paragraph,并向其中添加行。
    • 调用 display 方法显示整个段落的层次结构。

享元模式结合 Composite 模式的优势

  1. 减少内存占用

    • 通过共享文本样式的内部状态(字体、颜色、大小),可以显著减少内存使用。特别是在文档中大量字符使用相同的样式时,效果尤为明显。
  2. 提高创建和管理效率

    • 享元工厂可以缓存已经创建的文本样式对象,减少重复创建对象的开销。这对于频繁应用相同样式的场景非常有用。
  3. 层次结构的管理

    • 使用 Composite 模式可以方便地管理文档的层次结构,如段落、行和字符。通过组合节点和叶子节点,可以灵活地构建复杂的文本结构。
  4. 模块化设计

    • 将文本样式的内部状态和外部状态(字符)分离,使得系统的模块化设计更加清晰。这有助于提高代码的可维护性和可扩展性。

进一步优化

在实际应用中,可以进一步优化享元模式和 Composite 模式,例如:

  • 使用智能指针:使用 std::shared_ptr 来管理享元对象和文本组件的生命周期,确保对象在不再需要时被自动释放。
  • 多线程安全:如果应用是多线程的,可以在享元工厂中使用互斥锁(std::mutex)来确保线程安全。
  • 外部状态的封装:将外部状态(如字符位置)封装在一个结构体或类中,然后传递给享元对象,以提高代码的可读性和可维护性。

通过这些优化,可以进一步提高享元模式在文档编辑器中文本样式中的应用效果。希望这些解释和示例代码能帮助你更好地理解如何结合 Composite 模式和 Flyweight 模式来实现文档编辑器中的文本分层结构。

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com