Qua các series tự học về Design Pattern, Hôm nay cafedevn chia sẻ cho ace ví dụ và code cụ thể về cách sử dụng Flyweight design pattern với ngôn ngữ lập trình C++. Nhằm giúp ace hiểu rõ cách sử Pattern này với C++ một cách nhanh nhất và áp dụng nó vào thực tế.

Mô tả code

Flyweight mô tả cách chia sẻ các đối tượng, để việc sử dụng chúng ở mức độ chi tiết tốt mà không quá tốn kém. Một khái niệm chính là sự phân biệt giữa trạng thái “nội tại” và “ngoại tại”. Trạng thái bên trong bao gồm thông tin độc lập với ngữ cảnh của flyweight – thông tin có thể chia sẻ được (tức là tên, chiều rộng và chiều cao của mỗi Icon).

Nó được lưu trữ trong hạng cân bay (tức là hạng Icon). Trạng thái bên ngoài không thể được chia sẻ, nó phụ thuộc và thay đổi theo bối cảnh của Flyweight (tức là vị trí x, y mà góc trên bên trái của mỗi cá thể Icon sẽ được vẽ). Trạng thái bên ngoài được lưu trữ hoặc tính toán bởi máy khách và được chuyển đến trọng lượng bay khi một thao tác được gọi. Khách hàng không nên khởi tạo Flyweight trực tiếp, họ nên lấy chúng độc quyền từ một đối tượng FlyweightFactory để đảm bảo chúng được chia sẻ đúng cách.

Phần code

#include <iostream.h>
#include <string.h>

class Icon
{
  public:
    Icon(char *fileName)
    {
        strcpy(_name, fileName);
        if (!strcmp(fileName, "go"))
        {
            _width = 20;
            _height = 20;
        }
        if (!strcmp(fileName, "stop"))
        {
            _width = 40;
            _height = 40;
        }
        if (!strcmp(fileName, "select"))
        {
            _width = 60;
            _height = 60;
        }
        if (!strcmp(fileName, "undo"))
        {
            _width = 30;
            _height = 30;
        }
    }
    const char *getName()
    {
        return _name;
    }
    draw(int x, int y)
    {
        cout << "   drawing " << _name << ": upper left (" << x << "," << y << 
          ") - lower right (" << x + _width << "," << y + _height << ")" <<
          endl;
    }
  private:
    char _name[20];
    int _width;
    int _height;
};

class FlyweightFactory
{
  public:
    static Icon *getIcon(char *name)
    {
        for (int i = 0; i < _numIcons; i++)
          if (!strcmp(name, _icons[i]->getName()))
            return _icons[i];
        _icons[_numIcons] = new Icon(name);
        return _icons[_numIcons++];
    }
    static void reportTheIcons()
    {
        cout << "Active Flyweights: ";
        for (int i = 0; i < _numIcons; i++)
          cout << _icons[i]->getName() << " ";
        cout << endl;
    }
  private:
    enum
    {
        MAX_ICONS = 5
    };
    static int _numIcons;
    static Icon *_icons[MAX_ICONS];
};

int FlyweightFactory::_numIcons = 0;
Icon *FlyweightFactory::_icons[];

class DialogBox
{
  public:
    DialogBox(int x, int y, int incr): _iconsOriginX(x), _iconsOriginY(y),
      _iconsXIncrement(incr){}
    virtual void draw() = 0;
  protected:
    Icon *_icons[3];
    int _iconsOriginX;
    int _iconsOriginY;
    int _iconsXIncrement;
};

class FileSelection: public DialogBox
{
  public:
    FileSelection(Icon *first, Icon *second, Icon *third): DialogBox(100, 100,
      100)
    {
        _icons[0] = first;
        _icons[1] = second;
        _icons[2] = third;
    }
    void draw()
    {
        cout << "drawing FileSelection:" << endl;
        for (int i = 0; i < 3; i++)
          _icons[i]->draw(_iconsOriginX + (i *_iconsXIncrement), _iconsOriginY);
    }
};

class CommitTransaction: public DialogBox
{
  public:
    CommitTransaction(Icon *first, Icon *second, Icon *third): DialogBox(150,
      150, 150)
    {
        _icons[0] = first;
        _icons[1] = second;
        _icons[2] = third;
    }
    void draw()
    {
        cout << "drawing CommitTransaction:" << endl;
        for (int i = 0; i < 3; i++)
          _icons[i]->draw(_iconsOriginX + (i *_iconsXIncrement), _iconsOriginY);
    }
};

int main()
{
  DialogBox *dialogs[2];
  dialogs[0] = new FileSelection(FlyweightFactory::getIcon("go"),
    FlyweightFactory::getIcon("stop"), FlyweightFactory::getIcon("select"));
  dialogs[1] = new CommitTransaction(FlyweightFactory::getIcon("select"),
    FlyweightFactory::getIcon("stop"), FlyweightFactory::getIcon("undo"));

  for (int i = 0; i < 2; i++)
    dialogs[i]->draw();

  FlyweightFactory::reportTheIcons();
}

Kết quả:

drawing FileSelection:
   drawing go: upper left (100,100) - lower right (120,120)
   drawing stop: upper left (200,100) - lower right (240,140)
   drawing select: upper left (300,100) - lower right (360,160)
drawing CommitTransaction:
   drawing select: upper left (150,150) - lower right (210,210)
   drawing stop: upper left (300,150) - lower right (340,190)
   drawing undo: upper left (450,150) - lower right (480,180)
Active Flyweights: go stop select undo 

Cài ứng dụng cafedev để dễ dàng cập nhật tin và học lập trình mọi lúc mọi nơi tại đây.

Tài liệu từ cafedev:

Nếu bạn thấy hay và hữu ích, bạn có thể tham gia các kênh sau của cafedev để nhận được nhiều hơn nữa:

Chào thân ái và quyết thắng!

Đăng ký kênh youtube để ủng hộ Cafedev nha các bạn, Thanks you!