国产亚洲精品福利在线无卡一,国产精久久一区二区三区,亚洲精品无码国模,精品久久久久久无码专区不卡

當(dāng)前位置: 首頁 > news >正文

網(wǎng)站開發(fā)的對聯(lián)株洲疫情最新情況

網(wǎng)站開發(fā)的對聯(lián),株洲疫情最新情況,想學(xué)設(shè)計怎么入門在家自己學(xué),建設(shè)網(wǎng)站最新動態(tài)C設(shè)計模式(李建忠) 本文是學(xué)習(xí)筆記,如有侵權(quán),請聯(lián)系刪除。 參考鏈接 Youtube: C設(shè)計模式 Gtihub源碼與PPT:https://github.com/ZachL1/Bilibili-plus 豆瓣: 設(shè)計模式–可復(fù)用面向?qū)ο筌浖幕A(chǔ) 文章目錄 C設(shè)計?!?article class="baidu_pl">

C++設(shè)計模式(李建忠)

本文是學(xué)習(xí)筆記,如有侵權(quán),請聯(lián)系刪除。

參考鏈接

Youtube: C++設(shè)計模式

Gtihub源碼與PPT:https://github.com/ZachL1/Bilibili-plus

豆瓣: 設(shè)計模式–可復(fù)用面向?qū)ο筌浖幕A(chǔ)

文章目錄

  • C++設(shè)計模式(李建忠)
    • 8 工廠方法(Factory Method)
      • Motivation
      • 工廠方法定義
      • 工廠方法結(jié)構(gòu)
    • 9 抽象工廠(Abstract Factory)
      • Motivation
      • 抽象工廠定義
      • 抽象工廠結(jié)構(gòu)
    • 10 原型模式(Prototype)
      • 原型方法定義
      • 原型方法結(jié)構(gòu)
      • 原型模式和工廠方法的區(qū)別
    • 11 構(gòu)建器(Builder)
      • Motivation
      • Builder定義
      • Builder結(jié)構(gòu)
    • 12 單例模式(Singleton)
      • 單例模式定義
      • 單例模式結(jié)構(gòu)
    • 13 享元模式(Flyweight)
      • 享元模式定義
      • 享元模式結(jié)構(gòu)
    • 后記

“對象創(chuàng)建”模式

通過“對象創(chuàng)建”模式繞開new,來避免對象創(chuàng)建(new)過程 中所導(dǎo)致的緊耦合(依賴具體類),從而支持對象創(chuàng)建的穩(wěn)定。它是接口抽象之后的第一步工作。

典型模式

·Factory Method

·Abstract Factory

·Prototype

·Builder

8 工廠方法(Factory Method)

Motivation

在軟件系統(tǒng)中,經(jīng)常面臨著創(chuàng)建對象的工作;由于需求的變化,需要創(chuàng)建的對象的具體類型經(jīng)常變化。

如何應(yīng)對這種變化?如何繞過常規(guī)的對象創(chuàng)建方法(new),提供一種封裝機制來避免客戶程序和這種具體對象創(chuàng)建工作的緊耦合?

代碼示例:

MainForm方法調(diào)用Splitter將東西進行切分,有二進制文件切分、txt文件切分、圖片文件切分、視頻文件切分。

第一版:ISplitter * splitter= new BinarySplitter();這種寫法依賴于具體類,違反依賴倒置原則(高層模塊不應(yīng)該依賴于低層模塊,而是應(yīng)該依賴于抽象。同時,抽象不應(yīng)該依賴于具體實現(xiàn),具體實現(xiàn)應(yīng)該依賴于抽象。)

// 抽象基類
class ISplitter{
public:virtual void split()=0;virtual ~ISplitter(){}
};class BinarySplitter : public ISplitter{};class TxtSplitter: public ISplitter{};class PictureSplitter: public ISplitter{};class VideoSplitter: public ISplitter{};class MainForm : public Form
{TextBox* txtFilePath;TextBox* txtFileNumber;ProgressBar* progressBar;public:void Button1_Click(){ISplitter * splitter= new BinarySplitter();//依賴具體類splitter->split();}
};

第二版:具體調(diào)用工廠,MainForm不依賴于具體的類,而是依賴于抽象類和工廠基類。

class MainForm : public Form
{SplitterFactory*  factory;//工廠public:MainForm(SplitterFactory*  factory){this->factory=factory;}void Button1_Click(){ISplitter * splitter=factory->CreateSplitter(); //多態(tài)newsplitter->split();}
};

ISplitterFactory


//抽象類
class ISplitter{
public:virtual void split()=0;virtual ~ISplitter(){}
};//工廠基類
class SplitterFactory{
public:virtual ISplitter* CreateSplitter()=0;  // 創(chuàng)建對象virtual ~SplitterFactory(){}
};

FileSplitter文件:幾個具體的工廠繼承自SplitterFactory,實現(xiàn)虛函數(shù),實現(xiàn)具體類的創(chuàng)建

//具體類
class BinarySplitter : public ISplitter{};class TxtSplitter: public ISplitter{};class PictureSplitter: public ISplitter{};class VideoSplitter: public ISplitter{};//具體工廠
class BinarySplitterFactory: public SplitterFactory{
public:virtual ISplitter* CreateSplitter(){return new BinarySplitter();}
};class TxtSplitterFactory: public SplitterFactory{
public:virtual ISplitter* CreateSplitter(){return new TxtSplitter();}
};class PictureSplitterFactory: public SplitterFactory{
public:virtual ISplitter* CreateSplitter(){return new PictureSplitter();}
};class VideoSplitterFactory: public SplitterFactory{
public:virtual ISplitter* CreateSplitter(){return new VideoSplitter();}
};

工廠方法定義

定義一個用于創(chuàng)建對象的接口,讓子類決定實例化哪一個類。 Factory Method使一個類的實例化延遲到其子類。

具體到上面的代碼,用于創(chuàng)建對象的接口SplitterFactory,讓子類(BinarySplitterFactory,TxtSplitterFactory等具體工廠)決定實例化哪一個類。

在下列情況下可以使用Factory Method模式:
? 當(dāng)一個類不知道它所必須創(chuàng)建的對象的類的時候。
? 當(dāng)一個類希望由它的子類來指定它所創(chuàng)建的對象的時候。
? 當(dāng)類將創(chuàng)建對象的職責(zé)委托給多個幫助子類中的某一個,并且你希望將哪一個幫助子類是代理者這一信息局部化的時候。(classes delegate responsibility to one of several helper subclasses, and you want to localize the knowledge of which helper subclass is the delegate.)

工廠方法結(jié)構(gòu)

在這里插入圖片描述

參與者
? Product(ISplitter)
— 定義工廠方法所創(chuàng)建的對象的接口。
? ConcreteProduct(BinarySplitter,TxtSplitter,PictureSplitter,VideoSplitter)
— 實現(xiàn)Product接口。
? Creator(SplitterFactory)
— 聲明工廠方法,該方法返回一個Product類型的對象。Creator也可以定義一個工廠方法的缺省實現(xiàn),它返回一個缺省的ConcreteProduct對象。
— 可以調(diào)用工廠方法以創(chuàng)建一個Product對象。
? ConcreteCreator(BinarySplitterFactory,TxtSplitterFactory,PictureSplitterFactory,VideoSplitterFactory)
— 重定義工廠方法以返回一個ConcreteProduct實例。

工廠方法總結(jié)

Factory Method模式用于隔離類對象的使用者和具體類型之間的耦合關(guān)系。面對一個經(jīng)常變化的具體類型,緊耦合關(guān)系(new)會導(dǎo)致軟件的脆弱。

Factory Method模式通過面向?qū)ο?#xff08;多態(tài))的手法,將所要創(chuàng)建的具體對象工作延遲到子類,從而實現(xiàn)一種擴展(而非更改)的策略,較好地解決了這種緊耦合關(guān)系。

Factory Method模式解決單個對象的需求變化,缺點在于創(chuàng)建方法或者傳入的參數(shù)要相同。

9 抽象工廠(Abstract Factory)

Motivation

在軟件系統(tǒng)中,經(jīng)常面臨著一系列相互依賴的對象的創(chuàng)建工作;同時,由于需求的變化,往往存在更多系列對象的創(chuàng)建工作。如何應(yīng)對這種變化?如何繞過常規(guī)的對象創(chuàng)建方法(new),提供一種封裝機制來避免客戶程序和這種多系列具體對象創(chuàng)建工作的緊耦合?

代碼示例

創(chuàng)建數(shù)據(jù)訪問層,支持多種數(shù)據(jù)庫

第一版:不好的設(shè)計,綁定到具體的類

class EmployeeDAO{public:vector<EmployeeDO> GetEmployees(){SqlConnection* connection =new SqlConnection();connection->ConnectionString = "...";SqlCommand* command =new SqlCommand();command->CommandText="...";command->SetConnection(connection);SqlDataReader* reader = command->ExecuteReader();while (reader->Read()){}}
};

第二版:使用工廠方法,但是會遇到問題,使用的時候工廠之間有關(guān)聯(lián)性,必須是同一系列的,比如都是oracle數(shù)據(jù)庫的連接、命令、datareader等,不能是mysql的連接、orable的命令這種交叉使用。

// 三個對象必須是同系列(同組),有關(guān)聯(lián)性IDBConnectionFactory* dbConnectionFactory;IDBCommandFactory* dbCommandFactory;IDataReaderFactory* dataReaderFactory;

工廠方法的代碼如下


//數(shù)據(jù)庫訪問有關(guān)的基類
class IDBConnection{};
class IDBConnectionFactory{
public:virtual IDBConnection* CreateDBConnection()=0;
};class IDBCommand{};
class IDBCommandFactory{
public:virtual IDBCommand* CreateDBCommand()=0;
};class IDataReader{};
class IDataReaderFactory{
public:virtual IDataReader* CreateDataReader()=0;
};//支持SQL Server
class SqlConnection: public IDBConnection{};
class SqlConnectionFactory:public IDBConnectionFactory{};class SqlCommand: public IDBCommand{};
class SqlCommandFactory:public IDBCommandFactory{};class SqlDataReader: public IDataReader{};
class SqlDataReaderFactory:public IDataReaderFactory{};//支持Oracle
class OracleConnection: public IDBConnection{};class OracleCommand: public IDBCommand{};class OracleDataReader: public IDataReader{};class EmployeeDAO{// 三個對象必須是同系列(同組),有關(guān)聯(lián)性IDBConnectionFactory* dbConnectionFactory;IDBCommandFactory* dbCommandFactory;IDataReaderFactory* dataReaderFactory;public:vector<EmployeeDO> GetEmployees(){IDBConnection* connection =dbConnectionFactory->CreateDBConnection();connection->ConnectionString("...");IDBCommand* command =dbCommandFactory->CreateDBCommand();command->CommandText("...");command->SetConnection(connection); //關(guān)聯(lián)性IDBDataReader* reader = command->ExecuteReader(); //關(guān)聯(lián)性while (reader->Read()){}}
};

第三版:有關(guān)聯(lián)性的創(chuàng)建行為放在一起,合成一個工廠,這就是抽象工廠Abstract Factory


//數(shù)據(jù)庫訪問有關(guān)的基類
class IDBConnection{};class IDBCommand{};class IDataReader{};// 創(chuàng)建一個工廠:有關(guān)聯(lián)性的放在一起
class IDBFactory{
public:virtual IDBConnection* CreateDBConnection()=0;virtual IDBCommand* CreateDBCommand()=0;virtual IDataReader* CreateDataReader()=0;};//支持SQL Server
class SqlConnection: public IDBConnection{};
class SqlCommand: public IDBCommand{};
class SqlDataReader: public IDataReader{};class SqlDBFactory:public IDBFactory{
public:virtual IDBConnection* CreateDBConnection()=0;virtual IDBCommand* CreateDBCommand()=0;virtual IDataReader* CreateDataReader()=0;};//支持Oracle
class OracleConnection: public IDBConnection{};class OracleCommand: public IDBCommand{};class OracleDataReader: public IDataReader{};class EmployeeDAO{IDBFactory* dbFactory;public:vector<EmployeeDO> GetEmployees(){IDBConnection* connection =dbFactory->CreateDBConnection();connection->ConnectionString("...");IDBCommand* command =dbFactory->CreateDBCommand();command->CommandText("...");command->SetConnection(connection); //關(guān)聯(lián)性IDBDataReader* reader = command->ExecuteReader(); //關(guān)聯(lián)性while (reader->Read()){}}
};

抽象工廠定義

提供一個創(chuàng)建一系列相關(guān)或相互依賴對象的接口,而無需指定它們具體的類。

抽象工廠結(jié)構(gòu)

在這里插入圖片描述

參與者
? AbstractFactory (IDBFactory) — 聲明一個創(chuàng)建抽象產(chǎn)品對象的操作接口。
? ConcreteFactory (SqlDBFactory,OracleDBFactory等) — 實現(xiàn)創(chuàng)建具體產(chǎn)品對象的操作。
? AbstractProduct (IDBConnection,IDBCommand等) — 為一類產(chǎn)品對象聲明一個接口。
? ConcreteProduct (SqlConnection, OracleCommand等) — 定義一個將被相應(yīng)的具體工廠創(chuàng)建的產(chǎn)品對象。實現(xiàn)AbstractProduct接口。
? Client — 僅使用由AbstractFactory和AbstractProduct類聲明的接口。

協(xié)作
? 通常在運行時刻創(chuàng)建一個ConcreteFactory類的實例。這一具體的工廠創(chuàng)建具有特定實現(xiàn)的產(chǎn)品對象。為創(chuàng)建不同的產(chǎn)品對象,客戶應(yīng)使用不同的具體工廠。
? AbstractFactory將產(chǎn)品對象的創(chuàng)建延遲到它的ConcreteFactory子類。

要點總結(jié)

如果沒有應(yīng)對多系列對象構(gòu)建的需求變化,則沒有必要使用Abstract Factory模式,這時候使用簡單的工廠即可。

系列對象指的是在某一特定系列下的對象之間有相互依賴或相互作用的關(guān)系。不同系列的對象之間不能相互依賴。

10 原型模式(Prototype)

Motivation

在軟件系統(tǒng)中,經(jīng)常面臨著某些結(jié)構(gòu)復(fù)雜的對象的創(chuàng)建;由于需求的變化,這些對象經(jīng)常面臨著劇烈的變化,但是它們卻擁有比較穩(wěn)定一致的接口。

如何應(yīng)對這種變化?如何向客戶程序隔離出這些易變對象,從而使得依賴這些易變對象的客戶程序不隨著需求改變而改變?

代碼示例

//抽象類
class ISplitter{
public:virtual void split()=0;virtual ISplitter* clone()=0; //通過克隆自己來創(chuàng)建對象virtual ~ISplitter(){}};//具體類
class BinarySplitter : public ISplitter{
public:virtual ISplitter* clone(){return new BinarySplitter(*this);}
};class TxtSplitter: public ISplitter{
public:virtual ISplitter* clone(){return new TxtSplitter(*this);}
};class PictureSplitter: public ISplitter{
public:virtual ISplitter* clone(){return new PictureSplitter(*this);}
};class VideoSplitter: public ISplitter{
public:virtual ISplitter* clone(){return new VideoSplitter(*this);}
};

Client怎么用原型方法

class MainForm : public Form
{ISplitter*  prototype;//原型對象public:MainForm(ISplitter*  prototype){this->prototype=prototype;}void Button1_Click(){ISplitter * splitter=prototype->clone(); //克隆原型splitter->split();}
};

原型方法定義

用原型實例指定創(chuàng)建對象的種類,并且通過拷貝這些原型創(chuàng)建新的對象。

原型方法結(jié)構(gòu)

在這里插入圖片描述

參與者
? Prototype(ISplitter)
— 聲明一個克隆自身的接口。
? ConcretePrototype(BinarySplitter、TxtSplitter、PictureSplitter等)
— 實現(xiàn)一個克隆自身的操作。
? Client(MainForm)
— 讓一個原型克隆自身從而創(chuàng)建一個新的對象。

再給出chatGPT生成的原型方法的示例

原型方法(Prototype Pattern)是一種創(chuàng)建型設(shè)計模式,其主要目的是通過復(fù)制現(xiàn)有對象來創(chuàng)建新對象,而不是通過實例化類。這樣做可以避免直接使用構(gòu)造函數(shù)創(chuàng)建對象,提高對象的創(chuàng)建效率,同時也使得對象的創(chuàng)建更加靈活。原型方法通常包含一個克隆方法,用于復(fù)制對象。

以下是一個簡單的C++代碼示例,演示了原型方法的實現(xiàn):

#include <iostream>
#include <string>// 抽象原型類
class Prototype {
public:virtual Prototype* clone() const = 0;virtual void printInfo() const = 0;virtual ~Prototype() {}
};// 具體原型類 A
class ConcretePrototypeA : public Prototype {
public:Prototype* clone() const override {return new ConcretePrototypeA(*this);}void printInfo() const override {std::cout << "Concrete Prototype A" << std::endl;}
};// 具體原型類 B
class ConcretePrototypeB : public Prototype {
public:Prototype* clone() const override {return new ConcretePrototypeB(*this);}void printInfo() const override {std::cout << "Concrete Prototype B" << std::endl;}
};int main() {// 創(chuàng)建原型對象Prototype* prototypeA = new ConcretePrototypeA();Prototype* prototypeB = new ConcretePrototypeB();// 克隆對象Prototype* cloneA = prototypeA->clone();Prototype* cloneB = prototypeB->clone();// 打印信息prototypeA->printInfo();cloneA->printInfo();prototypeB->printInfo();cloneB->printInfo();// 釋放資源delete prototypeA;delete cloneA;delete prototypeB;delete cloneB;return 0;
}

在上述示例中,Prototype 是抽象原型類,其中包含了 cloneprintInfo 純虛函數(shù)。ConcretePrototypeAConcretePrototypeB 是具體的原型類,分別實現(xiàn)了這兩個函數(shù)。在 main 函數(shù)中,通過創(chuàng)建原型對象,然后克隆對象,最后打印信息,展示了原型方法的基本用法。

適用性

原型方法適用于那些需要頻繁創(chuàng)建對象,且對象的創(chuàng)建成本較高或創(chuàng)建過程復(fù)雜的情況。通過克隆現(xiàn)有對象來創(chuàng)建新對象,可以提高效率、簡化代碼,并且靈活應(yīng)對動態(tài)配置和變化。

原型模式和工廠方法的區(qū)別

  • 創(chuàng)建方式:
    • 原型模式通過克隆現(xiàn)有對象來創(chuàng)建新對象。
    • 工廠方法模式通過實現(xiàn)工廠方法來由子類決定創(chuàng)建的具體產(chǎn)品。
  • 關(guān)注點:
    • 原型模式關(guān)注對象的復(fù)制。
    • 工廠方法模式關(guān)注對象的創(chuàng)建。
  • 靈活性:
    • 原型模式更加靈活,允許在運行時動態(tài)選擇復(fù)制的對象。
    • 工廠方法模式更加固定,創(chuàng)建的對象由具體的子類工廠決定。

在實際應(yīng)用中,選擇使用哪種模式取決于需求和設(shè)計目標(biāo)。原型模式更適合對象創(chuàng)建時變化不大、但需要頻繁創(chuàng)建的情況,而工廠方法模式更適合在創(chuàng)建對象的類層次結(jié)構(gòu)變化頻繁時。

11 構(gòu)建器(Builder)

Motivation

?在軟件系統(tǒng)中,有時候面臨著“一個復(fù)雜對象”的創(chuàng)建工作,其通常由各個部分的子對象用一定的算法構(gòu)成;由于需求的變化,這個復(fù)雜對象的各個部分經(jīng)常面臨著劇烈的變化,但是將它們組合在一起的算法卻相對穩(wěn)定。

?如何應(yīng)對這種變化?如何提供一種“封裝機制”來隔離出“復(fù)雜對象的各個部分”的變化,從而保持系統(tǒng)中的“穩(wěn)定構(gòu)建算法”不隨著需求改變而改變?

代碼示例:建立各種房子,比如磚瓦房,高樓,別墅等房子


class House{//....
};class HouseBuilder {
public:House* GetResult(){return pHouse;}virtual ~HouseBuilder(){}
protected:House* pHouse;virtual void BuildPart1()=0;virtual void BuildPart2()=0;virtual void BuildPart3()=0;virtual void BuildPart4()=0;virtual void BuildPart5()=0;};class StoneHouse: public House{};// 石頭房子的創(chuàng)建,override HouseBuilder里面的流程
class StoneHouseBuilder: public HouseBuilder{
protected:virtual void BuildPart1(){//pHouse->Part1 = ...;}virtual void BuildPart2(){}virtual void BuildPart3(){}virtual void BuildPart4(){}virtual void BuildPart5(){}};// 房子具體構(gòu)建過程
class HouseDirector{public:// 有一個HouseBuilder的指針HouseBuilder* pHouseBuilder;HouseDirector(HouseBuilder* pHouseBuilder){this->pHouseBuilder=pHouseBuilder;}House* Construct(){ // 整個構(gòu)建流程是穩(wěn)定的pHouseBuilder->BuildPart1();for (int i = 0; i < 4; i++){pHouseBuilder->BuildPart2();}bool flag=pHouseBuilder->BuildPart3();if(flag){pHouseBuilder->BuildPart4();}pHouseBuilder->BuildPart5();return pHouseBuilder->GetResult();}
};int main() {// 創(chuàng)建石頭房子的建造者StoneHouseBuilder stoneHouseBuilder;// 創(chuàng)建房子Director,并指定建造者HouseDirector houseDirector(&stoneHouseBuilder);// 構(gòu)建房子House* stoneHouse = houseDirector.Construct();// 輸出結(jié)果if (stoneHouse != nullptr) {// 假設(shè) House 類有適當(dāng)?shù)妮敵龇椒?/span>// 這里只是簡單示例,實際使用時需要根據(jù)具體類的實現(xiàn)調(diào)用相應(yīng)的方法std::cout << "Stone House constructed." << std::endl;} else {std::cout << "Failed to construct Stone House." << std::endl;}// 釋放資源delete stoneHouse;return 0;
}

上述代碼涉及了Builder設(shè)計模式,包括以下幾個類:

  1. House 類:

    • 表示待構(gòu)建的產(chǎn)品,即房子。在示例中,StoneHouse 類是 House 的具體實現(xiàn)。
  2. HouseBuilder 抽象類:

    • 定義了構(gòu)建產(chǎn)品(房子)的抽象接口。具體的建造者(例如 StoneHouseBuilder)需要繼承這個抽象類并實現(xiàn)接口中的方法,以完成具體產(chǎn)品的構(gòu)建。
  3. StoneHouseBuilder 類:

    • HouseBuilder 的具體實現(xiàn),負責(zé)構(gòu)建石頭房子。它通過實現(xiàn)抽象接口中的方法來完成具體的建造流程。
  4. HouseDirector 類:

    • 起到指導(dǎo)建造的作用,通過構(gòu)造函數(shù)接收一個具體的建造者對象。通過調(diào)用建造者的方法,按照一定的構(gòu)建流程組織建造者完成產(chǎn)品的構(gòu)建。
  5. main 函數(shù):

    • main 函數(shù)中,創(chuàng)建了 StoneHouseBuilder 的實例,然后創(chuàng)建了一個 HouseDirector 的實例,并將建造者傳遞給導(dǎo)演。通過導(dǎo)演的 Construct 方法,按照一定的構(gòu)建流程構(gòu)建了石頭房子,并輸出結(jié)果。

總體而言,Builder設(shè)計模式的目的是將一個復(fù)雜對象的構(gòu)建與它的表示分離,使得同樣的構(gòu)建過程可以創(chuàng)建不同的表示。在這個示例中,HouseBuilder 抽象類定義了構(gòu)建房子的接口,StoneHouseBuilder 實現(xiàn)了具體的石頭房子構(gòu)建流程,而 HouseDirector 則負責(zé)協(xié)調(diào)建造者完成整個構(gòu)建流程。

Builder定義

將一個復(fù)雜對象的構(gòu)建與它的表示分離,使得同樣的構(gòu)建過程可以創(chuàng)建不同的表示。

Builder結(jié)構(gòu)

在這里插入圖片描述

參與者
? Builder(HouseBuilder)
— 為創(chuàng)建一個Product對象的各個部件指定抽象接口。
? ConcreteBuilder(StoneHouseBuilder等)
— 實現(xiàn)Builder的接口以構(gòu)造和裝配該產(chǎn)品的各個部件。
— 定義并明確它所創(chuàng)建的表示。
— 提供一個檢索產(chǎn)品的接口。
? Director(HouseDirector)
— 構(gòu)造一個使用Builder接口的對象。
? Product(這里沒表現(xiàn)出來)
— 表示被構(gòu)造的復(fù)雜對象。ConcreteBuilder創(chuàng)建該產(chǎn)品的內(nèi)部表示并定義它的裝配過程。
— 包含定義組成部件的類,包括將這些部件裝配成最終產(chǎn)品的接口。

Builder要點總結(jié)

?Builder 模式主要用于“分步驟構(gòu)建一個復(fù)雜的對象”。在這其中“分步驟”是一個穩(wěn)定的算法,而復(fù)雜對象的各個部分則經(jīng)常變化。

?變化點在哪里,封裝哪里—— Builder模式主要在于應(yīng)對“復(fù)雜對象各個部分”的頻繁需求變動。其缺點在于難以應(yīng)對“分步驟構(gòu)建算法”的需求變動。

?在Builder模式中,要注意不同語言中構(gòu)造器內(nèi)調(diào)用虛函數(shù)的差別(C++ vs. C#) 。

chatGPT給出的builder的例子

以下是一個簡單的C++示例代碼,演示Builder設(shè)計模式:

#include <iostream>
#include <string>// 產(chǎn)品類
class Product {
public:void AddPart(const std::string& part) {parts += part + " ";}void Show() const {std::cout << "Product Parts: " << parts << std::endl;}private:std::string parts;
};// 抽象建造者類
class Builder {
public:virtual void BuildPart1() = 0;virtual void BuildPart2() = 0;virtual Product* GetResult() = 0;
};// 具體建造者類
class ConcreteBuilder : public Builder {
public:ConcreteBuilder() {product = new Product();}void BuildPart1() override {product->AddPart("Part1");}void BuildPart2() override {product->AddPart("Part2");}Product* GetResult() override {return product;}private:Product* product;
};// 指導(dǎo)者類
class Director {
public:Director(Builder* builder) : builder(builder) {}void Construct() {builder->BuildPart1();builder->BuildPart2();}private:Builder* builder;
};int main() {// 創(chuàng)建具體建造者ConcreteBuilder concreteBuilder;// 創(chuàng)建指導(dǎo)者,并傳入具體建造者Director director(&concreteBuilder);// 指導(dǎo)者構(gòu)建產(chǎn)品director.Construct();// 獲取最終產(chǎn)品Product* product = concreteBuilder.GetResult();// 展示產(chǎn)品if (product != nullptr) {product->Show();delete product;}return 0;
}

在這個示例中,Product 表示最終構(gòu)建的復(fù)雜對象,Builder 是抽象建造者類,ConcreteBuilder 是具體建造者類,Director 是指導(dǎo)者類。通過指導(dǎo)者調(diào)用具體建造者的方法,最終得到構(gòu)建完成的產(chǎn)品。這個例子中的產(chǎn)品是簡單的包含兩個部分的字符串,實際應(yīng)用中可以根據(jù)需求定義更復(fù)雜的產(chǎn)品結(jié)構(gòu)。

“對象性能”模式

面向?qū)ο蠛芎玫亟鉀Q了“抽象”的問題,但是必不可免地要付出 一定的代價。對于通常情況來講,面向?qū)ο蟮某杀敬蠖伎梢院雎圆挥?。但是某些情況,面向?qū)ο笏鶐淼某杀颈仨氈斏魈幚怼?/p>

典型模式

·Singleton

·Flyweight

12 單例模式(Singleton)

Motivation

在軟件系統(tǒng)中,經(jīng)常有一些特殊的類,必須保證它們在系統(tǒng)中只存在一個實例,才能確保它們的邏輯正確性,以及良好的效率。

如何繞過常規(guī)的構(gòu)造器,提供一種機制來保證一個類只有一個實例?

這應(yīng)該是類設(shè)計者的責(zé)任,而不是使用者的責(zé)任。

單例模式代碼舉例:把構(gòu)造函數(shù)設(shè)置為private

class Singleton{
private:Singleton();Singleton(const Singleton& other);
public:static Singleton* getInstance();static Singleton* m_instance;
};Singleton* Singleton::m_instance=nullptr;//線程非安全版本
Singleton* Singleton::getInstance() {if (m_instance == nullptr) {m_instance = new Singleton();}return m_instance;
}//線程安全版本,但鎖的代價過高
Singleton* Singleton::getInstance() {Lock lock;if (m_instance == nullptr) {m_instance = new Singleton();}return m_instance;
}//雙檢查鎖,但由于內(nèi)存讀寫reorder不安全
Singleton* Singleton::getInstance() {if(m_instance==nullptr){Lock lock;if (m_instance == nullptr) {m_instance = new Singleton();}}return m_instance;
}//C++ 11版本之后的跨平臺實現(xiàn) (volatile)
std::atomic<Singleton*> Singleton::m_instance;
std::mutex Singleton::m_mutex;Singleton* Singleton::getInstance() {Singleton* tmp = m_instance.load(std::memory_order_relaxed);std::atomic_thread_fence(std::memory_order_acquire);//獲取內(nèi)存fenceif (tmp == nullptr) {std::lock_guard<std::mutex> lock(m_mutex);tmp = m_instance.load(std::memory_order_relaxed);if (tmp == nullptr) {tmp = new Singleton;std::atomic_thread_fence(std::memory_order_release);//釋放內(nèi)存fencem_instance.store(tmp, std::memory_order_relaxed);}}return tmp;
}

單例模式定義

保證一個類僅有一個實例,并提供一個訪問它的全局訪問點。

單例模式結(jié)構(gòu)

在這里插入圖片描述

參與者

? Singleton

— 定義一個 Instance 操作,允許客戶訪問它的唯一實例。 Instance 是一個類操作(即 Smalltalk 中的一個類方法和 C++ 中的一個靜態(tài)成員函數(shù))。

— 可能負責(zé)創(chuàng)建它自己的唯一實例。

協(xié)作

? 客戶只能通過 Singleton 的 Instance 操作訪問一個 Singleton 的實例。

下面是對單例模式雙檢查鎖的介紹

在單例模式中使用雙檢查鎖(DCL,Double-Checked Locking)時,可能會遇到一些問題,特別是在多線程環(huán)境下。在C++11之前的版本中,由于缺少內(nèi)存柵欄(memory barrier)的支持,可能導(dǎo)致DCL失效,從而造成線程安全性問題。

主要問題包括:

  1. 內(nèi)存寫入和讀取的重排序問題:
    在一些編譯器和硬件架構(gòu)中,對于指令的執(zhí)行順序可能會發(fā)生重排序,導(dǎo)致在實例化對象時,成員變量的內(nèi)存分配可能在對象構(gòu)造之前,從而使其他線程在獲取到非空但尚未構(gòu)造完全的對象。

  2. 缺乏內(nèi)存柵欄:
    在C++11之前,C++標(biāo)準(zhǔn)庫并沒有提供內(nèi)存柵欄的概念,而DCL依賴于內(nèi)存柵欄來保證寫入和讀取的順序性。缺少內(nèi)存柵欄可能導(dǎo)致指令亂序執(zhí)行,使得雙檢查鎖失效。

  3. 編譯器優(yōu)化問題:
    一些編譯器可能會對代碼進行優(yōu)化,可能會在保證正確性的情況下對代碼進行調(diào)整,從而導(dǎo)致DCL失效。

在C++11及以后的版本中,引入了std::atomic等特性,可以更好地保證內(nèi)存可見性和順序性,從而避免了上述問題。因此,如果在C++11及以后的環(huán)境中,使用std::atomic可以解決DCL的一些問題。

// Singleton.h
#pragma once#include <atomic>
#include <mutex>class Singleton {
public:// 獲取單例實例的靜態(tài)方法static Singleton* Instance();private:// 私有構(gòu)造函數(shù),確保單例不能通過其他方式實例化Singleton() {}private:// 使用std::atomic提供的原子操作,確保多線程環(huán)境下的安全性static std::atomic<Singleton*> m_instance;// 用于保護實例化過程的互斥鎖static std::mutex m_mutex;
};// Singleton.cpp
#include "Singleton.h"// 初始化靜態(tài)成員變量
std::atomic<Singleton*> Singleton::m_instance(nullptr);
std::mutex Singleton::m_mutex;Singleton* Singleton::Instance() {// 使用std::atomic加載實例,確保內(nèi)存可見性Singleton* tmp = m_instance.load(std::memory_order_relaxed);std::atomic_thread_fence(std::memory_order_acquire);if (tmp == nullptr) {// 使用互斥鎖保護實例化過程std::lock_guard<std::mutex> lock(m_mutex);tmp = m_instance.load(std::memory_order_relaxed);if (tmp == nullptr) {// 實例化單例對象tmp = new Singleton;// 使用內(nèi)存順序和std::atomic_thread_fence確保內(nèi)存可見性和順序性std::atomic_thread_fence(std::memory_order_release);// 存儲單例對象的指針m_instance.store(tmp, std::memory_order_relaxed);}}return tmp;
}

這里,使用std::atomic提供的內(nèi)存順序和std::atomic_thread_fence來保證正確的內(nèi)存可見性和順序性。在C++11及以后的環(huán)境中,這種方式是相對安全的。

13 享元模式(Flyweight)

Motivation

在軟件系統(tǒng)采用純粹對象方案的問題在于大量細粒度的對象會很快充斥在系統(tǒng)中,從而帶來很高的運行時代價——主要指內(nèi)存需求方面的代價。

如何在避免大量細粒度對象問題的同時,讓外部客戶程序仍然能夠透明地適用面向?qū)ο蟮姆绞絹磉M行操作?

代碼舉例:,創(chuàng)建字體對象時,同一個key的字體對象只有一個,而不是有很多

// Font.h
#pragma once#include <string>class Font {
private:// 字體對象的唯一標(biāo)識符std::string key;// 字體對象的狀態(tài)(可能包含其他屬性,這里未具體展示)// ....public:// 構(gòu)造函數(shù),根據(jù)傳入的 key 初始化字體對象Font(const std::string& key) : key(key) {// ...}
};// FontFactory.h
#pragma once#include <map>
#include "Font.h"class FontFactory {
private:// 存儲已創(chuàng)建的字體對象,key 是字體對象的唯一標(biāo)識符,value 是對應(yīng)的字體對象指針std::map<std::string, Font*> fontPool;public:// 獲取字體對象Font* GetFont(const std::string& key);// 清理字體池void clear();
};// FontFactory.cpp
#include "FontFactory.h"Font* FontFactory::GetFont(const std::string& key) {// 查找字體池中是否已存在對應(yīng) key 的字體對象auto iter = fontPool.find(key);if (iter != fontPool.end()) {// 如果存在,則直接返回已有的字體對象return iter->second;} else {// 如果不存在,則創(chuàng)建新的字體對象,并加入字體池Font* font = new Font(key);fontPool[key] = font;return font;}
}void FontFactory::clear() {// 清理字體池中的所有字體對象for (auto& entry : fontPool) {delete entry.second;}fontPool.clear();
}

享元模式定義

運用共享技術(shù)有效地支持大量細粒度的對象。

享元模式結(jié)構(gòu)

在這里插入圖片描述

參與者
? Flyweight
— 描述一個接口,通過這個接口 flyweight 可以接受并作用于外部狀態(tài)。
? ConcreteFlyweight
— 實現(xiàn) Flyweight 接口,并為內(nèi)部狀態(tài)(如果有的話)增加存儲空間。
ConcreteFlyweight 對象必須是可共享的。它所存儲的狀態(tài)必須是內(nèi)部的;即,它必須獨立于 ConcreteFlyweight 對象的場景。
? UnsharedConcreteFlyweight
— 并非所有的 Flyweight 子類都需要被共享。 Flyweight 接口使共享成為可能,但它并不強制共享。在 Flyweight 對象結(jié)構(gòu)的某些層次, UnsharedConcreteFlyweight 對象通常將 ConcreteFlyweight 對象作為子節(jié)點。
? FlyweightFactory
— 創(chuàng)建并管理 flyweight 對象。
— 確保合理地共享 flyweight。當(dāng)用戶請求一個 flyweight 時, FlyweightFactory 對象提供一個已創(chuàng)建的實例或者創(chuàng)建一個(如果不存在的話)。
? Client
— 維持一個對 flyweight 的引用。
— 計算或存儲一個(多個) flyweight 的外部狀態(tài)。

下圖說明如何共享flyweight

在這里插入圖片描述

chatGPT給出的享元模式的例子

以下是一個簡單的 C++ 代碼例子,演示了享元模式的實現(xiàn)。這個例子以文本編輯器中的字符格式化為場景。

#include <iostream>
#include <map>// 享元接口
class CharacterFormat {
public:virtual void applyFormat() const = 0;
};// 具體享元類,代表不同的字符格式
class BoldFormat : public CharacterFormat {
public:void applyFormat() const override {std::cout << "Applying Bold Format\n";}
};class ItalicFormat : public CharacterFormat {
public:void applyFormat() const override {std::cout << "Applying Italic Format\n";}
};class UnderlineFormat : public CharacterFormat {
public:void applyFormat() const override {std::cout << "Applying Underline Format\n";}
};// 享元工廠類,負責(zé)創(chuàng)建和管理享元對象
class CharacterFormatFactory {
private:std::map<std::string, CharacterFormat*> formatPool;public:CharacterFormat* getFormat(const std::string& key) {auto iter = formatPool.find(key);if (iter != formatPool.end()) {return iter->second;} else {CharacterFormat* format = nullptr;if (key == "Bold") {format = new BoldFormat();} else if (key == "Italic") {format = new ItalicFormat();} else if (key == "Underline") {format = new UnderlineFormat();}formatPool[key] = format;return format;}}
};// 客戶端代碼
int main() {CharacterFormatFactory formatFactory;// 用戶輸入的字符格式std::string userInput = "Bold";// 通過享元工廠獲取或創(chuàng)建字符格式對象CharacterFormat* format = formatFactory.getFormat(userInput);// 應(yīng)用字符格式if (format) {format->applyFormat();} else {std::cout << "Invalid Format\n";}// 釋放資源delete format;return 0;
}

在這個例子中,CharacterFormat 是享元接口,而 BoldFormat、ItalicFormat、UnderlineFormat 是具體的享元類。CharacterFormatFactory 是享元工廠類,負責(zé)創(chuàng)建和管理享元對象。在客戶端代碼中,用戶輸入字符格式的信息,通過享元工廠獲取或創(chuàng)建相應(yīng)的字符格式對象,并應(yīng)用該格式。這樣,相同的字符格式對象可以被多次共享,減少了資源的重復(fù)創(chuàng)建。

要點總結(jié)

面向?qū)ο蠛芎玫亟鉀Q了抽象性的問題,但是作為一個運行在機器 中的程序?qū)嶓w,我們需要考慮對象的代價問題。Flyweight主要解 決面向?qū)ο蟮拇鷥r問題,一般不觸及面向?qū)ο蟮某橄笮詥栴}。

Flyweight采用對象共享的做法來降低系統(tǒng)中對象的個數(shù),從而降 低細粒度對象給系統(tǒng)帶來的內(nèi)存壓力。在具體實現(xiàn)方面,要注意對 象狀態(tài)的處理。

對象的數(shù)量太大從而導(dǎo)致對象內(nèi)存開銷加大——什么樣的數(shù)量才 算大?這需要我們仔細的根據(jù)具體應(yīng)用情況進行評估,而不能憑空 臆斷。

后記

截至2024年1月17日14點48分,學(xué)習(xí)了Factory Method, Abstract Factory, Prototype, Builder, Singleton, Flyweight模式。下午繼續(xù)學(xué)習(xí)。

http://aloenet.com.cn/news/35034.html

相關(guān)文章:

  • 多種成都網(wǎng)站建設(shè)全網(wǎng)推廣外包公司
  • 珠寶 網(wǎng)站模板免費seo快速收錄工具
  • 網(wǎng)站logo怎么修改北京網(wǎng)絡(luò)推廣有哪些公司
  • 建站平臺選擇建議全球訪問量top100網(wǎng)站
  • 網(wǎng)站開發(fā)服務(wù)費入什么科目重慶網(wǎng)站快速排名提升
  • 西安專業(yè)網(wǎng)站建設(shè)價格引擎搜索對人類記憶的影響
  • 門戶網(wǎng)站建設(shè)和檢務(wù)公開情況自查報告免費建一個自己的網(wǎng)站
  • 網(wǎng)站開發(fā) 保修期網(wǎng)絡(luò)推廣文案怎么寫
  • 會計實帳培訓(xùn)上海百度搜索優(yōu)化
  • 怎么用自己的電腦做網(wǎng)站主機企業(yè)管理培訓(xùn)課程視頻
  • 別人做的網(wǎng)站怎么打開2022網(wǎng)站seo
  • 網(wǎng)站開發(fā)人員職位晉升空間深圳龍崗區(qū)布吉街道
  • 小程序開發(fā)價格深圳百度seo公司
  • 自動搭建網(wǎng)站源碼優(yōu)就業(yè)seo
  • wordpress 遷移到hexo抖音seo怎么做
  • 哪些網(wǎng)站可以免費做推廣呢南沙seo培訓(xùn)
  • 做網(wǎng)站空間放哪些文件夾網(wǎng)頁模板圖片
  • 點餐網(wǎng)站模板深圳谷歌推廣公司
  • 福州網(wǎng)站開發(fā)si7.cc必應(yīng)收錄提交入口
  • 做二手家電網(wǎng)站怎樣?xùn)|莞網(wǎng)絡(luò)優(yōu)化服務(wù)商
  • 網(wǎng)站開發(fā)費用如何入賬企點下載
  • 專業(yè)企業(yè)網(wǎng)站搭建服務(wù)有創(chuàng)意的網(wǎng)絡(luò)廣告案例
  • 國外域名的網(wǎng)站怎么做seo快速排名軟件網(wǎng)站
  • 網(wǎng)站制作方案怎么做seo排名優(yōu)化推薦
  • 醫(yī)院網(wǎng)站建設(shè)方案計劃書北大青鳥培訓(xùn)機構(gòu)靠譜嗎
  • 那個網(wǎng)站可以接做網(wǎng)頁私活惠州網(wǎng)絡(luò)營銷公司
  • 淘寶軟件營銷網(wǎng)站建設(shè)品牌推廣策略包括哪些內(nèi)容
  • 快看漫畫小程序入口關(guān)鍵詞優(yōu)化靠譜推薦
  • 鎮(zhèn)海區(qū)住房和建設(shè)交通局網(wǎng)站友情鏈接名詞解釋
  • 旅游區(qū)網(wǎng)站開發(fā)蕭山區(qū)seo關(guān)鍵詞排名