赞
踩
GitHub - FengJungle/DesignPattern: Design pattern demo code
再不学简单工厂模式,就真的要去工厂搬砖啦~_冯Jungle的博客-CSDN博客
通过以下的例子可见,只需要提供产品名称作为参数,传入工厂的方法中,即可得到对应产品。抽象产品类中并没有提供公共方法的实现,而是在各个具体产品类中根据各自产品情况实现。
当然,简单工厂模式存在明显的不足。假设有一天Jungle想玩网球了,该怎么办呢?你肯定会说,这还不容易吗?再从抽象产品类派生出一个Tennis类,并在工厂类的getSportProduct方法中增加“productName == "Tennis”的条件分支即可。的确如此,但是这明显违背了开闭原则(对扩展开放,对修改关闭),即在扩展功能时修改了已有的代码。另一方面,简单工厂模式所有的判断逻辑都在工厂类中实现,一旦工厂类设计故障,则整个系统都受之影响!

例1
SimpleFactory.h
- #ifndef _SIMPLE_FACTORY_
- #define _SIMPLE_FACTORY_
-
- #include <iostream>
-
- // 抽象类
- class AbstractSportProduct{
- public:
- virtual void printName() = 0;
- virtual void play() = 0;
- };
-
- class Basketball : public AbstractSportProduct{
- public:
- void printName(){std::cout << "Jungle get Basketball\n";}
- void play(){std::cout << "Jungle play Basketball\n";}
- };
-
- class Football : public AbstractSportProduct{
- public:
- Football(){
- printName();
- play();
- }
- void printName(){std::cout << "Jungle get Football\n";}
- void play(){std::cout << "Jungle play Football\n";}
- };
-
- class Volleyball : public AbstractSportProduct{
- public:
- void printName(){std::cout << "Jungle get Volleyball\n";}
- void play(){std::cout << "Jungle play Volleyball\n";}
- };
-
- class Factory{
- public:
- std::shared_ptr<AbstractSportProduct> getSportProduct(std::string productName){
- std::shared_ptr<AbstractSportProduct> pro;
- if(productName == "Basketball"){
- pro = std::make_shared<Basketball>();
- }else if (productName == "Football"){
- pro = std::make_shared<Football>();
- }else if (productName == "Volleyball"){
- pro = std::make_shared<Volleyball>();
- }
- return pro;
- }
- };
-
- #endif

main.cpp
- #include <iostream>
- #include "SimpleFactory.h"
-
- int main(){
- std::shared_ptr<Factory> f = std::make_shared<Factory>();
- std::shared_ptr<AbstractSportProduct> pro = f->getSportProduct("Basketball");
- pro->printName();
- pro->play();
-
- std::cout << "-------------------------\n";
- pro = f->getSportProduct("Football");
-
- std::cout << "-------------------------\n";
- pro = f->getSportProduct("Volleyball");
- pro->printName();
- pro->play();
-
- return 0;
- }


如果Jungle想玩网球(Tennis),只需要增加一个棒球工厂(TennisFacory),然后在客户端代码中修改具体工厂类的类名,而原有的类的代码无需修改。由此可看到,相较简单工厂模式,工厂方法模式更加符合开闭原则。工厂方法是使用频率最高的设计模式之一,是很多开源框架和API类库的核心模式。

例1
FactoryMethod.h
- #ifndef __FACTORY_METHOD__
- #define __FACTORY_METHOD__
-
- #include <iostream>
-
- // 抽象产品类
- class AbstractSportProduct{
- public:
- virtual void printName() = 0;
- virtual void play() = 0;
- };
-
- class Basketball :public AbstractSportProduct{
- public:
- void printName(){std::cout << "Jungle get Basketball\n";}
- void play(){std::cout << "Jungle play Basketball\n";}
- };
-
- class Football :public AbstractSportProduct{
- public:
- Football(){
- printName();
- play();
- }
- void printName(){std::cout << "Jungle get Football\n";}
- void play(){std::cout << "Jungle play Football\n";}
- };
-
- class Volleyball :public AbstractSportProduct{
- public:
- void printName(){std::cout << "Jungle get Volleyball\n";}
- void play(){std::cout << "Jungle play Volleyball\n";}
- };
-
- // 抽象工厂类
- class AbstractFactory{
- public:
- virtual std::shared_ptr<AbstractSportProduct> getSportProduct() = 0;
- };
-
- class BasketballFactory : public AbstractFactory{
- public:
- std::shared_ptr<AbstractSportProduct> getSportProduct() {
- return std::make_shared<Basketball>();
- }
- };
-
- class FootballFactory : public AbstractFactory{
- public:
- std::shared_ptr<AbstractSportProduct> getSportProduct() {
- return std::make_shared<Football>();
- }
- };
-
- class VolleyballFactory : public AbstractFactory{
- public:
- std::shared_ptr<AbstractSportProduct> getSportProduct() {
- return std::make_shared<Volleyball>();
- }
- };
-
- #endif

main.cpp
- #include <iostream>
- #include "FactoryMethod.h"
-
- int main(){
- std::shared_ptr<BasketballFactory> f = std::make_shared<BasketballFactory>();
- std::shared_ptr<AbstractSportProduct> pro = f->getSportProduct();
- pro->printName();
- pro->play();
-
- std::cout << "------------------------------\n";
- std::shared_ptr<FootballFactory> f1 = std::make_shared<FootballFactory>();
- pro = f1->getSportProduct();
-
- std::cout << "------------------------------\n";
- std::shared_ptr<VolleyballFactory> f2 = std::make_shared<VolleyballFactory>();
- pro = f2->getSportProduct();
- pro->printName();
- pro->play();
-
- return 0;
- }


回顾之前的设计模式,简单工厂模式所有逻辑都封装在工厂类中,工厂根据客户提供的产品名字创建对应产品的对象实例;工厂方法模式将产品的创建过程放到了具体工厂类中,每一个工厂可以创建一个具体产品,由此可能会创建许多工厂类。很多时候,一个工厂不只是生产一种产品,而是生产一类产品,比如一个体育用品工厂,可以生产篮球、足球、排球等多种产品。此时我们可以把这些相关的产品归纳为一个“产品族”,由同一个工厂来生产,这即是Jungle今天要学习的抽象工厂模式。

例1
AbstractFactory.h
- #ifndef __ABSTRACT_FACTORY__
- #define __ABSTRACT_FACTORY__
-
- #include <iostream>
-
- // 抽象球类
- class AbstractBall{
- public:
- virtual void play() = 0;
- };
-
- class Basketball : public AbstractBall{
- public:
- void play() {std::cout << "Jungle play Basketball\n";}
- };
-
- class Football : public AbstractBall{
- public:
- void play() {std::cout << "Jungle play Football\n";}
- };
-
- // 抽象衬衫类
- class AbstractShirt{
- public:
- virtual void wearShirt() = 0;
- };
-
- class BasketballShirt : public AbstractShirt{
- public:
- void wearShirt() {std::cout << "Jungle wear Basketball Shirt\n";}
- };
-
- class FootballShirt : public AbstractShirt{
- public:
- void wearShirt() {std::cout << "Jungle wear Football Shirt\n";}
- };
-
- // 抽象工厂类
- class AbstractFactory{
- public:
- virtual std::shared_ptr<AbstractBall> getBall() = 0;
- virtual std::shared_ptr<AbstractShirt> getShirt() = 0;
- };
-
- class BasketballFactory : public AbstractFactory{
- public:
- std::shared_ptr<AbstractBall> getBall(){
- std::cout << "Jungle get Basketball\n";
- return std::make_shared<Basketball>();
- }
- std::shared_ptr<AbstractShirt> getShirt(){
- std::cout << "Jungle get Basketball Shirt\n";
- return std::make_shared<BasketballShirt>();
- }
- };
-
- class FootballFactory : public AbstractFactory{
- public:
- std::shared_ptr<AbstractBall> getBall(){
- std::cout << "Jungle get Football\n";
- return std::make_shared<Football>();
- }
- std::shared_ptr<AbstractShirt> getShirt(){
- std::cout << "Jungle get Football Shirt\n";
- return std::make_shared<FootballShirt>();
- }
- };
-
- #endif

main.cpp
- #include <iostream>
- #include "AbstractFactory.h"
-
- int main(){
- std::shared_ptr<BasketballFactory> f = std::make_shared<BasketballFactory>();
- std::shared_ptr<AbstractBall> ab = f->getBall();
- std::shared_ptr<AbstractShirt> as = f->getShirt();
- ab->play();
- as->wearShirt();
-
- std::cout << "---------------------------------\n";
- std::shared_ptr<FootballFactory> f1 = std::make_shared<FootballFactory>();
- ab = f1->getBall();
- as = f1->getShirt();
- ab->play();
- as->wearShirt();
-
- return 0;
- }



例1
BuilderPattern.h
- #ifndef __BUILDER_PATTERN__
- #define __BUILDER_PATTERN__
-
- #include <iostream>
-
- // 产品类
- class House{
- public:
- void setFloor(std::string iFloor){
- this->floor = iFloor;
- }
-
- void setWall(std::string iWall){
- this->wall = iWall;
- }
-
- void setRoof(std::string iRoof){
- this->roof = iRoof;
- }
-
- void printfHouseInfo() {
- std::cout << "floor: " << floor << "\n";
- std::cout << "wall: " << wall << "\n";
- std::cout << "roof: " << roof << "\n";
- }
-
- private:
- std::string floor;
- std::string wall;
- std::string roof;
- };
-
- // 抽象建造者
- class AbstractBuilder{
- public:
- AbstractBuilder(){house = std::make_shared<House>();}
-
- virtual void buildFloor() = 0;
- virtual void buildWall() = 0;
- virtual void buildRoof() = 0;
- virtual std::shared_ptr<House> getHouse() = 0;
- std::shared_ptr<House> house;
- };
-
- // 具体建造者A
- class ConcreteBuilderA : public AbstractBuilder{
- public:
- void buildFloor() {
- house->setFloor("Floor_A");
- }
- void buildWall(){
- house->setWall("Wall_A");
- }
- void buildRoof(){
- house->setRoof("Roof_A");
- }
- std::shared_ptr<House> getHouse(){
- return house;
- }
- };
-
- // 具体建造者B
- class ConcreteBuilderB : public AbstractBuilder{
- public:
- void buildFloor() {
- house->setFloor("Floor_B");
- }
- void buildWall(){
- house->setWall("Wall_B");
- }
- void buildRoof(){
- house->setRoof("Roof_B");
- }
- std::shared_ptr<House> getHouse(){
- return house;
- }
- };
-
- // 指挥者
- class Director{
- public:
- void setBuilder(std::shared_ptr<AbstractBuilder> ibuilder){
- builder = ibuilder;
- }
- // 封装组装流程,返回建造结果
- std::shared_ptr<House> construct(){
- builder->buildFloor();
- builder->buildRoof();
- builder->buildWall();
- return builder->getHouse();
- }
-
- private:
- std::shared_ptr<AbstractBuilder> builder;
- };
-
- #endif

main.cpp
- #include <iostream>
- #include "BuilderPattern.h"
-
- int main(){
- // 指定具体建造者A
- std::shared_ptr<Director> d = std::make_shared<Director>();
- std::shared_ptr<ConcreteBuilderA> cba = std::make_shared<ConcreteBuilderA>();
- d->setBuilder(cba);
- std::shared_ptr<House> h = d->construct();
- h->printfHouseInfo();
-
- std::cout << "---------------------------\n";
- // 指定具体建造者B
- std::shared_ptr<ConcreteBuilderB> cbb = std::make_shared<ConcreteBuilderB>();
- d->setBuilder(cbb);
- h = d->construct();
- h->printfHouseInfo();
-
- return 0;
- }


原型模式通过复制一个已有对象来获取更多相同或者相似的对象。
例1
报错如下:Segmentation fault: 11 空指针问题
PrototypePattern.h
- #ifndef __PROTOTYPE_PATTERN__
- #define __PROTOTYPE_PATTERN__
-
- #include <iostream>
-
- class WorkModel{
- public:
- void setWorkModelName(std::string imodelName){
- modelName = imodelName;
- }
- std::string getWorkModelName(){
- return modelName;
- }
- private:
- std::string modelName;
- };
-
- class ConcreteWork {
- public:
- std::shared_ptr<ConcreteWork> clone(){
- std::shared_ptr<ConcreteWork> cw = std::make_shared<ConcreteWork>();
- cw->setIdNum(idNum);
- cw->setIdName(idName);
- cw->setIWorkModel(iWorkModel);
- return cw;
- }
- std::shared_ptr<WorkModel> getIWorkModel(){
- return iWorkModel;
- }
- void setIdNum(int iIdNum){
- idNum = iIdNum;
- }
- void setIdName(std::string iIdName){
- idName = iIdName;
- }
- void setIWorkModel(std::shared_ptr<WorkModel> iIWorkModel){
- iWorkModel = iIWorkModel;
- }
- void printWorkInfo(){
- std::cout << "Name: " << idName << "\n";
- std::cout << "Num: " << idNum << "\n";
- std::cout << "ModelName: " << iWorkModel->getWorkModelName() << "\n";
- }
-
- private:
- int idNum;
- std::string idName;
- std::shared_ptr<WorkModel> iWorkModel;
- };
-
- #endif

main.cpp
- #include <iostream>
- #include "PrototypePattern.h"
-
- int main(){
- std::shared_ptr<ConcreteWork> singleWork = std::make_shared<ConcreteWork>();
- singleWork->setIdNum(1001);
- singleWork->setIdName("single");
- std::shared_ptr<WorkModel> singleWorkModel = singleWork->getIWorkModel();
- // 错:singleWorkModel是空指针,执行setWorkModelName()会报错!
- singleWorkModel->setWorkModelName("single_model");
- std::cout << "single完成了作业:\n";
-
- return 0;
- }

改正如下:
PrototypePattern.h
- #ifndef __PROTOTYPE_PATTERN__
- #define __PROTOTYPE_PATTERN__
-
- #include <iostream>
-
- class WorkModel{
- public:
- void setWorkModelName(std::string imodelName){
- modelName = imodelName;
- }
- std::string getWorkModelName(){
- return modelName;
- }
- private:
- std::string modelName;
- };
-
- class ConcreteWork {
- public:
- std::shared_ptr<ConcreteWork> clone(){
- std::shared_ptr<ConcreteWork> cw = std::make_shared<ConcreteWork>();
- cw->setIdNum(idNum);
- cw->setIdName(idName);
- cw->setIWorkModel(iWorkModel);
- return cw;
- }
- void setIdNum(int iIdNum){
- idNum = iIdNum;
- }
- void setIdName(std::string iIdName){
- idName = iIdName;
- }
- void setIWorkModel(std::shared_ptr<WorkModel> iIWorkModel){
- iWorkModel = iIWorkModel;
- }
- void printWorkInfo(){
- std::cout << "Name: " << idName << "\n";
- std::cout << "Num: " << idNum << "\n";
- std::cout << "ModelName: " << iWorkModel->getWorkModelName() << "\n";
- }
-
- private:
- int idNum;
- std::string idName;
- std::shared_ptr<WorkModel> iWorkModel;
- };
-
- #endif

main.cpp
- #include <iostream>
- #include "PrototypePattern.h"
-
- int main(){
- std::shared_ptr<ConcreteWork> singleWork = std::make_shared<ConcreteWork>();
- singleWork->setIdNum(1001);
- singleWork->setIdName("single");
- std::shared_ptr<WorkModel> workModel = std::make_shared<WorkModel>();
- workModel->setWorkModelName("single_model");
- singleWork->setIWorkModel(workModel);
- singleWork->printWorkInfo();
-
- std::shared_ptr<ConcreteWork> jungleWork = singleWork->clone();
- std::cout << "jungle正在抄作业...\n";
-
- std::cout << "jungle抄完了,正在改名字和学号,否则会被老师查出来...\n";
- jungleWork->setIdNum(1002);
- jungleWork->setIdName("jungle");
- workModel = std::make_shared<WorkModel>();
- workModel->setWorkModelName("jungle_Model");
- jungleWork->setIWorkModel(workModel);
-
- std::cout << "jungle也完成了作业:\n";
- jungleWork->printWorkInfo();
-
- return 0;
- }


Singleton.h
- #ifndef __SINGLETON_H__
- #define __SINGLETON_H__
-
- #include <iostream>
- #include <mutex>
-
- std::mutex m_mutex;
-
- // 懒汉单例模式
- class Singleton_Lazy{
- public:
- static std::shared_ptr<Singleton_Lazy> getInstance(){
- std::cout << "singleton lazy mode.\n";
- if(instance == nullptr){
- m_mutex.lock(); // 加锁
- if(instance == nullptr){
- std::cout << "创建新的实例.\n";
- instance = std::make_shared<Singleton_Lazy>();
- }
- m_mutex.unlock(); // 解锁
- }
- return instance;
- }
-
- private:
- static std::shared_ptr<Singleton_Lazy> instance;
- };
-
- std::shared_ptr<Singleton_Lazy> Singleton_Lazy::instance = nullptr;
-
- // 饿汉单例模式
- class Singleton_Hungry{
- public:
- static std::shared_ptr<Singleton_Hungry> getInstance(){
- std::cout << "singleton hungry mode.\n";
- instance = std::make_shared<Singleton_Hungry>();
- return instance;
- }
- private:
- static std::shared_ptr<Singleton_Hungry> instance;
- };
-
- std::shared_ptr<Singleton_Hungry> Singleton_Hungry::instance = nullptr;
-
- #endif

main.cpp
- #include <iostream>
- #include "Singleton.h"
- #include <pthread.h>
-
- #define THREAD_NUM 6
-
- void* callSingleton_Lazy(void*){
- std::shared_ptr<Singleton_Lazy> sl = Singleton_Lazy::getInstance();
- std::cout << "线程编号: " << pthread_self() << "\n";
- }
-
- void* callSingleton_Hungry(void*){
- std::shared_ptr<Singleton_Hungry> sh = Singleton_Hungry::getInstance();
- std::cout << "线程编号: " << pthread_self() << "\n";
- }
-
- int main(){
- pthread_t threads_pool[THREAD_NUM];
- int tids[THREAD_NUM];
- // 线程具有属性,用pthread_attr_t表示,在对该结构进行处理之前必须进行初始化,在使用后需要对其去除初始化。
- pthread_attr_t attr;
- void* status;
-
- // 创建 pthread_attr_t
- pthread_attr_init(&attr);
-
- // 线程的分离状态决定一个线程以什么样的方式来终止自己。在默认情况下线程是非分离状态的,这种情况下,原有的线程等待创建的线程结束。
- // 只有当pthread_join()函数返回时,创建的线程才算终止,才能释放自己占用的系统资源。
- // PTHREAD _CREATE_JOINABLE(非分离线程)
- pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
-
- for(int i = 0; i < THREAD_NUM; i++){
- if(i < THREAD_NUM / 2){
- // 线程创建 pthread_create
- tids[i] = pthread_create(&threads_pool[i], nullptr, callSingleton_Lazy, (void*)&i);
- }else {
- std::cout << "-----------------\n";
- tids[i] = pthread_create(&threads_pool[i], nullptr, callSingleton_Hungry, (void*)&i);
- }
- if(tids[i]){
- std::cout << "Error: unable to create thread.\n";
- return 0;
- }
- }
-
- // 销毁 pthread_attr_t
- pthread_attr_destroy(&attr);
- for(int i = 0; i < THREAD_NUM; i++){
- // pthread_join 主线程阻塞
- tids[i] = pthread_join(threads_pool[i], &status);
- if(tids[i]){
- std::cout << "Error: unable to join.\n";
- return 0;
- }
- }
- std::cout << "main exiting.\n";
-
- return 0;
- }


AdapterPattern.h
- #ifndef __ADAPTERPATTERN_H__
- #define __ADAPTERPATTERN_H__
-
- #include <iostream>
-
- // 适配者类DxfParser
- class DxfParser{
- public:
- void parseFile(){
- std::cout << "Parse dxf file\n";
- }
- };
-
- // 适配者类PathPlanner
- class PathPlanner{
- public:
- void calculate(){
- std::cout << "calculate path\n";
- }
- };
-
- class Adapter{
- public:
- void pathPlanning(){
- std::cout << "pathPlanning\n";
- dxfParser->parseFile();
- pathPlanner->calculate();
- }
- private:
- std::shared_ptr<DxfParser> dxfParser;
- std::shared_ptr<PathPlanner> pathPlanner;
- };
-
- #endif

main.cpp
- #include <iostream>
- #include "AdapterPattern.h"
-
- int main(){
- std::shared_ptr<Adapter> adapter = std::make_shared<Adapter>();
- adapter->pathPlanning();
-
- return 0;
- }

BridgePattern.h
- #ifndef __BRIDGE_PATTERN_H__
- #define __BRIDGE_PATTERN_H__
-
- #include <iostream>
-
- // 抽象类Game
- class Game{
- public:
- virtual void play() = 0;
- };
-
- class GameA : public Game {
- public:
- void play(){
- std::cout << "Jungle玩游戏A\n";
- }
- };
-
- class GameB : public Game {
- public:
- void play(){
- std::cout << "Jungle玩游戏B\n";
- }
- };
-
- // 抽象类Phone
- class Phone{
- public:
- virtual void setUpGame(std::shared_ptr<Game> igame) = 0;
- virtual void play() = 0;
- private:
- std::shared_ptr<Game> game;
- };
-
- class PhoneA : public Phone{
- public:
- void setUpGame(std::shared_ptr<Game> igame){
- game = igame;
- }
- void play(){
- game->play();
- }
- private:
- std::shared_ptr<Game> game;
- };
-
- class PhoneB : public Phone{
- public:
- void setUpGame(std::shared_ptr<Game> igame){
- game = igame;
- }
- void play(){
- game->play();
- }
- private:
- std::shared_ptr<Game> game;
- };
-
- #endif

main.cpp
- #include <iostream>
- #include "BridgePattern.h"
-
- int main(){
- // Jungle买了PhoneA品牌的手机,想玩游戏A
- std::shared_ptr<PhoneA> phoneA = std::make_shared<PhoneA>();
- std::shared_ptr<GameA> gameA = std::make_shared<GameA>();
- phoneA->setUpGame(gameA);
- phoneA->play();
-
- std::cout << "----------------\n";
- // Jungle想在这个手机上玩游戏B
- std::shared_ptr<GameB> gameB = std::make_shared<GameB>();
- phoneA->setUpGame(gameB);
- phoneA->play();
-
- return 0;
- }


CompositePattern.h
- #ifndef __COMPOSITE_PATTERN_H__
- #define __COMPOSITE_PATTERN_H__
-
- #include <iostream>
- #include <vector>
-
- // 抽象构件
- class Component{
- public:
- Component(){}
- Component(std::string iName){name = iName;}
- // 增加一个部门或办公室
- virtual void add(std::shared_ptr<Component> com) = 0;
- // 撤销一个部门或办公室
- virtual void remove(std::shared_ptr<Component> com) = 0;
- //
- virtual std::shared_ptr<Component> getChild(int num) = 0;
- // 各部门操作
- virtual void operation() = 0;
- std::string getName(){
- return name;
- }
-
- private:
- std::string name;
- };
-
- // 叶子构件:办公室
- // 没实现operation(),所以抽象类Component的子类Office也是抽象类,不能实例化!
- class Office : public Component{
- public:
- Office(){}
- Office(std::string iName){name = iName;}
- void add(std::shared_ptr<Component> com){
- std::cout << "not support!\n";
- }
- void remove(std::shared_ptr<Component> com){
- std::cout << "not support!\n";
- }
- std::shared_ptr<Component> getChild(int num){
- std::cout << "not support!\n";
- return nullptr;
- }
-
- private:
- std::string name;
- };
-
- // 叶子构件:行政办公室
- // 虽然没实现add()、remove()、getChild(),但其基类Office已经实现过了这部分 ——>
- // 所以派生类AdminOffice虽然只实现了operation(), 但其仍然可以实例化!
- class AdminOffice : public Office{
- public:
- AdminOffice(){}
- AdminOffice(std::string iName){name = iName;}
-
- void operation(){
- std::cout << "-----Administration Office: " << name << "\n";
- }
-
- private:
- std::string name;
- };
-
- // 叶子构件:教务办公室
- // 可以实例化,原因同AdminOffice
- class DeanOffice : public Office{
- public:
- DeanOffice(){}
- DeanOffice(std::string iName){name = iName;}
-
- void operation(){
- std::cout << "-----Dean Office: " << name << "\n";
- }
-
- private:
- std::string name;
- };
-
- // 容器构件SubComponent
- // 实现了Component的所有纯虚函数,所以SubComponent可以实例化!
- class SubComponent : public Component{
- public:
- SubComponent(){}
- SubComponent(std::string iName){
- name = iName;
- }
- void add(std::shared_ptr<Component> com){
- componentList.push_back(com);
- }
- void remove(std::shared_ptr<Component> com){
- for(int i = 0; i < componentList.size(); i++){
- // 遍历查找
- if(componentList[i]->getName() == com->getName()){
- componentList.erase(componentList.begin() + 1);
- break;
- }
- }
- }
- std::shared_ptr<Component> getChild(int num){
- return componentList[num];
- }
- void operation(){
- std::cout << name << "\n";
- for(int i = 0; i < componentList.size(); i++){
- componentList[i]->operation();
- }
- }
-
- private:
- std::string name;
- // 构件列表
- std::vector<std::shared_ptr<Component> > componentList;
- };
-
- #endif

main.cpp
- #include <iostream>
- #include "CompositePattern.h"
-
- int main(){
- std::shared_ptr<SubComponent> head = std::make_shared<SubComponent>("总部");
- std::shared_ptr<SubComponent> sichuanBranch = std::make_shared<SubComponent>("四川分部");
- std::shared_ptr<AdminOffice> office1 = std::make_shared<AdminOffice>("行政办公室");
- std::shared_ptr<DeanOffice> office2 = std::make_shared<DeanOffice>("教务办公室");
-
- std::shared_ptr<SubComponent> cdBranch = std::make_shared<SubComponent>("成都分部");
- std::shared_ptr<SubComponent> myBranch = std::make_shared<SubComponent>("绵阳分部");
- std::shared_ptr<AdminOffice> office3 = std::make_shared<AdminOffice>("行政办公室");
- std::shared_ptr<DeanOffice> office4 = std::make_shared<DeanOffice>("教务办公室");
-
- std::shared_ptr<AdminOffice> office5 = std::make_shared<AdminOffice>("行政办公室");
- std::shared_ptr<DeanOffice> office6 = std::make_shared<DeanOffice>("教务办公室");
-
- std::shared_ptr<AdminOffice> office7 = std::make_shared<AdminOffice>("行政办公室");
- std::shared_ptr<DeanOffice> office8 = std::make_shared<DeanOffice>("教务办公室");
-
- cdBranch->add(office5);
- cdBranch->add(office6);
-
- myBranch->add(office7);
- myBranch->add(office8);
-
- sichuanBranch->add(office3);
- sichuanBranch->add(office4);
- sichuanBranch->add(cdBranch);
- sichuanBranch->add(myBranch);
-
- head->add(office1);
- head->add(office2);
- head->add(sichuanBranch);
-
- head->operation();
-
- return 0;
- }


DecoratorPattern.h
- #ifndef __DECORATOR_PATTERN_H__
- #define __DECORATOR_PATTERN_H__
-
- #include <iostream>
-
- // 抽象构件
- class Component{
- public:
- virtual void operation() = 0;
- };
-
- // 具体构件
- class Phone : public Component{
- public:
- void operation(){
- std::cout << "手机\n";
- }
- };
-
- class Decorator : public Component{
- public:
- void operation(){
- component->operation();
- }
- void setComponent(std::shared_ptr<Component> iComponent){
- component = iComponent;
- }
- std::shared_ptr<Component> getComponent(){
- return component;
- }
-
- private:
- std::shared_ptr<Component> component;
- };
-
- // 具体装饰类:手机壳
- class DecoratorShell : public Decorator{
- public:
- void operation(){
- getComponent()->operation();
- std::cout << "安装手机壳\n";
- }
- };
-
- // 具体装饰类:手机贴纸
- class DecoratorSticker : public Decorator{
- public:
- void operation(){
- getComponent()->operation();
- std::cout << "贴卡通贴纸ֽ\n";
- }
- };
-
- // 具体装饰类:挂绳
- class DecoratorRope : public Decorator{
- public:
- void operation(){
- getComponent()->operation();
- std::cout << "系手机挂绳\n";
- }
- };
-
- #endif

main.cpp
- #include <iostream>
- #include "DecoratorPattern.h"
-
- int main(){
- std::cout << "Jungle's first phone\n";
- std::shared_ptr<Phone> p = std::make_shared<Phone>();
- std::shared_ptr<DecoratorShell> ds = std::make_shared<DecoratorShell>();
- ds->setComponent(p);
- ds->operation();
-
- std::cout << "\nJungle's second phone\n";
- std::shared_ptr<DecoratorSticker> dst = std::make_shared<DecoratorSticker>();
- dst->setComponent(ds);
- dst->operation();
-
- std::cout << "\nJungle's third phone\n";
- std::shared_ptr<DecoratorRope> dr = std::make_shared<DecoratorRope>();
- dr->setComponent(dst);
- dr->operation();
-
- return 0;
- }


FacadePattern.h
- /*
- * @Author: error: error: git config user.name & please set dead value or install git && error: git config user.email & please set dead value or install git & please set dead value or install git
- * @Date: 2021-08-19 11:19:57
- * @LastEditors: error: error: git config user.name & please set dead value or install git && error: git config user.email & please set dead value or install git & please set dead value or install git
- * @LastEditTime: 2023-03-13 10:29:14
- * @FilePath: /cpp_test/FacadePattern.h
- * @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE#
- */
- #ifndef __FACADE_PATTERN_H__
- #define __FACADE_PATTERN_H__
-
- #include <iostream>
-
- class Memory{
- public:
- void selfCheck(){
- std::cout << "memory selfchecking......\n";
- }
- };
-
- class Cpu{
- public:
- void run(){
- std::cout << "running cpu......\n";
- }
- };
-
- class HardDisk{
- public:
- void read(){
- std::cout << "reading hardDisk......\n";
- }
- };
-
- class Os{
- public:
- void load(){
- std::cout << "loading os.....\n";
- }
- };
-
- class Facade{
- public:
- void powerOn(){
- std::cout << "power on……\n";
- memory->selfCheck();
- cpu->run();
- hardDisk->read();
- os->load();
- std::cout << "ready!\n";
- }
-
- private:
- std::shared_ptr<Memory> memory;
- std::shared_ptr<Cpu> cpu;
- std::shared_ptr<HardDisk> hardDisk;
- std::shared_ptr<Os> os;
- };
-
- #endif

main.cpp
- #include <iostream>
- #include "FacadePattern.h"
-
- int main(){
- std::shared_ptr<Facade> f = std::make_shared<Facade>();
- f->powerOn();
-
- return 0;
- }

FlyweightPattern.h
- /*
- * @Author: error: error: git config user.name & please set dead value or install git && error: git config user.email & please set dead value or install git & please set dead value or install git
- * @Date: 2021-08-19 11:19:57
- * @LastEditors: error: error: git config user.name & please set dead value or install git && error: git config user.email & please set dead value or install git & please set dead value or install git
- * @LastEditTime: 2023-03-13 11:23:46
- * @FilePath: /cpp_test/FlyweightPattern.h
- * @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
- */
- #ifndef __FLYPATTERN_PATTERN_H__
- #define __FLYPATTERN_PATTERN_H__
-
- #include <iostream>
- #include <vector>
- #include <mutex>
-
- std::mutex m_mutex;
-
- // 抽象享元类
- class NetDevice{
- public:
- virtual std::string getName() = 0;
- void print(int portNum){
- std::cout << "NetDevice: " << getName() << ", port: " << portNum << "\n";
- }
- };
-
- // 具体享元类:集线器
- class Hub : public NetDevice{
- public:
- std::string getName(){
- return "集线器";
- }
- };
-
- // 具体享元类:交换机
- class Switch : public NetDevice{
- public:
- std::string getName(){
- return "交换机";
- }
- };
-
- // 享元工厂类
- class NetDeviceFactory{
- public:
- NetDeviceFactory(){
- std::shared_ptr<Hub> hub = std::make_shared<Hub>();
- std::shared_ptr<Switch> switcher = std::make_shared<Switch>();
- devicePool.push_back(hub);
- devicePool.push_back(switcher);
- }
-
- std::shared_ptr<NetDevice> getNetDevice(char c){
- if(c == 'S'){
- return devicePool[1];
- }else if (c == 'H')
- {
- return devicePool[0];
- }else{
- std::cout << "wrong input!\n";
- }
- return nullptr;
- }
-
- // 单例模式:返回享元工厂类的唯一实例
- static std::shared_ptr<NetDeviceFactory> getFactory(){
- if(instance == nullptr){
- m_mutex.lock();
- if(instance == nullptr){
- instance = std::make_shared<NetDeviceFactory>();
- }
- m_mutex.unlock();
- }
- return instance;
- }
-
- private:
- static std::shared_ptr<NetDeviceFactory> instance;
- // 共享池
- std::vector<std::shared_ptr<NetDevice> > devicePool;
- };
-
- std::shared_ptr<NetDeviceFactory> NetDeviceFactory::instance = nullptr;
-
- #endif

main.cpp
- #include <iostream>
- #include "FlyweightPattern.h"
-
- int main(){
- std::shared_ptr<NetDeviceFactory> netDeviceFactory = NetDeviceFactory::getFactory();
-
- // 客户端1获取一个hub
- std::shared_ptr<NetDevice> netDevice1 = netDeviceFactory->getNetDevice('H');
- netDevice1->print(1);
- // 客户端2获取一个hub
- std::shared_ptr<NetDevice> netDevice2 = netDeviceFactory->getNetDevice('H');
- netDevice2->print(2);
- std::cout << "判断两个hub是否是同一个:\n";
- std::cout << "netDevice1: " << netDevice1 << ", netDevice2: " << netDevice2 << "\n\n\n";
-
- // 客户端3获取一个switch
- std::shared_ptr<NetDevice> netDevice3 = netDeviceFactory->getNetDevice('S');
- netDevice3->print(1);
- // 客户端4获取一个switch
- std::shared_ptr<NetDevice> netDevice4 = netDeviceFactory->getNetDevice('S');
- netDevice4->print(2);
- std::cout << "判断两个switch是否是同一个:\n";
- std::cout << "netDevice3: " << netDevice3 << ", netDevice4: " << netDevice4 << "\n";
-
- return 0;
- }


报错如下:
ProxyPattern.h
- #ifndef __FLYPATTERN_PATTERN_H__
- #define __FLYPATTERN_PATTERN_H__
-
- #include <iostream>
- #include "time.h"
-
- // 抽象主题角色
- class Subject{
- public:
- virtual void method() = 0;
- };
-
- // 真实主题角色
- class RealSubject : public Subject{
- public:
- void method(){
- std::cout << "调用业务方法\n";
- }
- };
-
- // Log类
- class Log{
- public:
- void getLog(){
- std::cout << "调用日志\n";
- }
- };
-
- // 代理类
- class Proxy : public Subject{
- public:
- void method(){
- log->getLog();
- realSubject->method();
- std::cout << "方法method()调用成功!\n";
- }
-
- private:
- std::shared_ptr<RealSubject> realSubject;
- std::shared_ptr<Log> log;
- };
-
- #endif

main.cpp
- #include <iostream>
- #include "ProxyPattern.h"
-
- int main(){
- std::shared_ptr<Proxy> p = std::make_shared<Proxy>();
- p->method();
-
- return 0;
- }

修改如下:
ProxyPattern.h
- #ifndef __FLYPATTERN_PATTERN_H__
- #define __FLYPATTERN_PATTERN_H__
-
- #include <iostream>
- #include "time.h"
-
- // 抽象主题角色
- class Subject{
- public:
- virtual void method() = 0;
- };
-
- // 真实主题角色
- class RealSubject : public Subject{
- public:
- void method(){
- std::cout << "调用业务方法\n";
- }
- };
-
- // Log类
- class Log{
- public:
- void getLog(){
- std::cout << "调用日志\n";
- }
- };
-
- // 代理类
- class Proxy : public Subject{
- public:
- Proxy(){
- realSubject = std::make_shared<RealSubject>();
- log = std::make_shared<Log>();
- }
-
- void method(){
- log->getLog();
- realSubject->method();
- std::cout << "方法method()调用成功!\n";
- }
-
- private:
- std::shared_ptr<RealSubject> realSubject;
- std::shared_ptr<Log> log;
- };
-
- #endif


也可修改如下:
ProxyPattern.h
- #ifndef __FLYPATTERN_PATTERN_H__
- #define __FLYPATTERN_PATTERN_H__
-
- #include <iostream>
- #include "time.h"
-
- // 抽象主题角色
- class Subject{
- public:
- virtual void method() = 0;
- };
-
- // 真实主题角色
- class RealSubject : public Subject{
- public:
- void method(){
- std::cout << "调用业务方法\n";
- }
- };
-
- // Log类
- class Log{
- public:
- void getLog(){
- std::cout << "调用日志\n";
- }
- };
-
- // 代理类
- class Proxy : public Subject{
- public:
- void method(){
- realSubject = std::make_shared<RealSubject>();
- log = std::make_shared<Log>();
- log->getLog();
- realSubject->method();
- std::cout << "方法method()调用成功!\n";
- }
-
- private:
- std::shared_ptr<RealSubject> realSubject;
- std::shared_ptr<Log> log;
- };
-
- #endif


ChainOfResponsibility.h
- #ifndef __CHAIN_OF_RESPONSIBILITY_PATTERN_H__
- #define __CHAIN_OF_RESPONSIBILITY_PATTERN_H__
-
- #include <iostream>
-
- // 请求:票据
- class Bill{
- public:
- Bill(){}
- Bill(int iId, std::string iName, double iAccount){
- id = iId;
- name = iName;
- account = iAccount;
- }
-
- void print(){
- std::cout << "id: " << id << "\n";
- std::cout << "name: " << name << "\n";
- std::cout << "account: " << account << "\n\n";
- }
- double getAccount(){
- return account;
- }
-
- private:
- int id;
- std::string name;
- double account;
- };
-
- // 抽象处理者
- class Approver{
- public:
- // 添加上级
- void setSuperior(std::shared_ptr<Approver> iApprover){
- superior = iApprover;
- }
- // 处理请求
- virtual void handleRequest(std::shared_ptr<Bill> bill) = 0;
-
- std::shared_ptr<Approver> getSuperior(){
- return superior;
- }
-
- std::string getName(){
- return name;
- }
-
- void setName(std::string iName){
- name = iName;
- }
-
- private:
- std::shared_ptr<Approver> superior;
- std::string name;
- };
-
- // 具体处理者:组长
- class GroupLeader : public Approver{
- public:
- GroupLeader(){}
- GroupLeader(std::string iName){
- setName(iName);
- }
-
- void handleRequest(std::shared_ptr<Bill> bill){
- if(bill->getAccount() < 10){
- std::cout << "组长: " << getName() << "处理了该票据,票据信息:\n";
- bill->print();
- }else{
- std::cout << "组长无权处理,转交上级……\n";
- getSuperior()->handleRequest(bill);
- }
- }
- };
-
- // 具体处理者:主管
- class Head : public Approver{
- public:
- Head(){}
- Head(std::string iName){
- setName(iName);
- }
-
- void handleRequest(std::shared_ptr<Bill> bill){
- if(bill->getAccount() >= 10 && bill->getAccount() < 30){
- std::cout << "主管: " << getName() << "处理了该票据,票据信息:\n";
- bill->print();
- }else{
- std::cout << "主管无权处理,转交上级……\n";
- getSuperior()->handleRequest(bill);
- }
- }
- };
-
- // 具体处理者:经理
- class Manager : public Approver{
- public:
- Manager(){}
- Manager(std::string iName){
- setName(iName);
- }
-
- void handleRequest(std::shared_ptr<Bill> bill){
- if(bill->getAccount() >= 30 && bill->getAccount() < 60){
- std::cout << "经理: " << getName() << "处理了该票据,票据信息:\n";
- bill->print();
- }else{
- std::cout << "经理无权处理,转交上级……\n";
- getSuperior()->handleRequest(bill);
- }
- }
- };
-
- // 具体处理者:老板
- class Boss : public Approver{
- public:
- Boss(){}
- Boss(std::string iName){
- setName(iName);
- }
-
- void handleRequest(std::shared_ptr<Bill> bill){
- std::cout << "老板: " << getName() << "处理了该票据,票据信息:\n";
- bill->print();
- }
- };
-
- #endif

main.cpp
- #include <iostream>
- #include "ChainOfResponsibility.h"
-
- int main(){
- std::shared_ptr<GroupLeader> groupLeader = std::make_shared<GroupLeader>("孙组长");
- std::shared_ptr<Head> head = std::make_shared<Head>("兵主管");
- std::shared_ptr<Manager> manager = std::make_shared<Manager>("春经理");
- std::shared_ptr<Boss> boss = std::make_shared<Boss>("孙老板");
-
- // 添加上级
- groupLeader->setSuperior(head);
- head->setSuperior(manager);
- manager->setSuperior(boss);
-
- // 创建报销单
- std::shared_ptr<Bill> bill1 = std::make_shared<Bill>(1, "Jungle", 8);
- std::shared_ptr<Bill> bill2 = std::make_shared<Bill>(2, "Lucy", 14.4);
- std::shared_ptr<Bill> bill3 = std::make_shared<Bill>(3, "Jack", 32.9);
- std::shared_ptr<Bill> bill4 = std::make_shared<Bill>(4, "Tom", 89);
-
- // 全部先交给组长审批
- groupLeader->handleRequest(bill1);
- groupLeader->handleRequest(bill2);
- groupLeader->handleRequest(bill3);
- groupLeader->handleRequest(bill4);
-
- return 0;
- }


CommandPattern.h
- #ifndef __COMMAND_PATTERN_H__
- #define __COMMAND_PATTERN_H__
-
- #include <iostream>
- #include <vector>
-
- // 命令队列类
- #define COMMAND_QUEUE
-
- // 抽象命令类
- class Command{
- public:
- virtual void execute() = 0;
- };
-
- // 接收者:电灯类
- class Lamp{
- public:
- void on(){
- lampState = true;
- std::cout << "Lamp is on\n";
- }
- void off(){
- lampState = false;
- std::cout << "Lamp is off\n";
- }
- bool getLampState(){
- return lampState;
- }
-
- private:
- bool lampState;
- };
-
- // 接收者:风扇类
- class Fan{
- public:
- void on(){
- fanState = true;
- std::cout << "Fan is on\n";
- }
- void off(){
- fanState = false;
- std::cout << "Fan is off\n";
- }
- bool getFanState(){
- return fanState;
- }
-
- private:
- bool fanState;
- };
-
- // 具体命令类 LampCommand
- class LampCommand : public Command{
- public:
- LampCommand(){
- lamp = std::make_shared<Lamp>();
- }
- void execute(){
- if(lamp->getLampState()){
- lamp->off();
- }else{
- lamp->on();
- }
- }
-
- private:
- std::shared_ptr<Lamp> lamp;
- };
-
- // 具体命令类 FanCommand
- class FanCommand : public Command{
- public:
- FanCommand(){
- fan = std::make_shared<Fan>();
- }
- void execute(){
- if(fan->getFanState()){
- fan->off();
- }else{
- fan->on();
- }
- }
-
- private:
- std::shared_ptr<Fan> fan;
- };
-
- // 调用者 Button
- class Button{
- public:
- void setCommand(std::shared_ptr<Command> iCom){
- command = iCom;
- }
- void touch(){
- std::cout << "触摸开关:\n";
- command->execute();
- }
-
- private:
- std::shared_ptr<Command> command;
- };
-
- #ifdef COMMAND_QUEUE
-
- // 命令队列类
- class CommandQueue{
- public:
- void addCommand(std::shared_ptr<Command> com){
- commandQueue.push_back(com);
- }
- void execute(){
- for(int i = 0; i < commandQueue.size(); i++){
- commandQueue[i]->execute();
- }
- }
-
- private:
- std::vector<std::shared_ptr<Command> > commandQueue;
- };
-
- // 调用者 Button2
- class Button2{
- public:
- void setCommandQueue(std::shared_ptr<CommandQueue> iCommandQueue){
- commandQueue = iCommandQueue;
- }
- void touch(){
- std::cout << "触摸开关:\n";
- commandQueue->execute();
- }
-
- private:
- std::shared_ptr<CommandQueue> commandQueue;
- };
-
- #endif
-
- #endif

main.cpp
- #include <iostream>
- #include "CommandPattern.h"
-
- int main(){
- // 按钮
- std::shared_ptr<Button> bt = std::make_shared<Button>();
- // 按钮控制电灯
- std::shared_ptr<LampCommand> lc = std::make_shared<LampCommand>();
- bt->setCommand(lc);
- bt->touch();
- bt->touch();
- bt->touch();
- bt->touch();
- std::cout << "\n\n";
-
- std::shared_ptr<FanCommand> fc = std::make_shared<FanCommand>();
- bt->setCommand(fc);
- bt->touch();
- bt->touch();
- bt->touch();
- bt->touch();
- std::cout << "-------------------------\n";
-
- #ifdef COMMAND_QUEUE
- std::shared_ptr<Button2> bt2 = std::make_shared<Button2>();
- std::shared_ptr<CommandQueue> cq = std::make_shared<CommandQueue>();
- cq->addCommand(lc);
- cq->addCommand(fc);
- bt2->setCommandQueue(cq);
- bt2->touch();
-
- #endif
- return 0;
- }


Memento.h
- #ifndef __MEMENTO_H__
- #define __MEMENTO_H__
-
- #include <iostream>
-
- class Memento{
- public:
- Memento(){}
- Memento(int iVersion, std::string iDate, std::string iLabel){
- version = iVersion;
- date = iDate;
- label = iLabel;
- }
- int getVersion(){
- return version;
- }
- std::string getDate(){
- return date;
- }
- std::string getLabel(){
- return label;
- }
-
- private:
- int version;
- std::string date;
- std::string label;
- };
-
- #endif

Originator.h
- #ifndef __CODEVERSION_H__
- #define __CODEVERSION_H__
-
- #include <iostream>
- #include "Memento.h"
-
- class CodeVersion{
- public:
- CodeVersion(){
- version = 0;
- date = "1900-01-01";
- label = "none";
- }
- CodeVersion(int iVersion, std::string iDate, std::string iLabel){
- version = iVersion;
- date = iDate;
- label = iLabel;
- }
- std::shared_ptr<Memento> save(){
- return std::make_shared<Memento>(version, date, label);
- }
- std::shared_ptr<Memento> commit(){
- return std::make_shared<Memento>(version, date, label);
- }
- void restore(std::shared_ptr<Memento> mem){
- version = mem->getVersion();
- date = mem->getDate();
- label = mem->getLabel();
- }
-
- private:
- int version;
- std::string date;
- std::string label;
- };
-
- #endif

CodeManager.h
- #ifndef __CODEMANAGER_H__
- #define __CODEMANAGER_H__
-
- #include <iostream>
- #include <vector>
- #include "Memento.h"
-
- class CodeManager{
- public:
- void commit(std::shared_ptr<Memento> mem){
- std::cout << "version: " << mem->getVersion() <<
- ", date: " << mem->getDate() << ", label: " << mem->getLabel() << "\n";
- mementoList.push_back(mem);
- }
- std::shared_ptr<Memento> switchToPointedVersion(int index){
- mementoList.erase(mementoList.begin() + mementoList.size() - index, mementoList.end());
- return mementoList[mementoList.size() - 1];
- }
- void codeLog(){
- for (int i = 0; i < mementoList.size(); i++){
- std::cout << "version: " << mementoList[i]->getVersion() <<
- ", date: " << mementoList[i]->getDate() << ", label: " << mementoList[i]->getLabel() << "\n";
- }
- }
-
- private:
- std::vector<std::shared_ptr<Memento> > mementoList;
- };
-
- #endif

main.cpp
- #include <iostream>
- #include "Originator.h"
- #include "CodeManager.h"
-
- int main(){
- std::shared_ptr<CodeManager> Jungle = std::make_shared<CodeManager>();
- std::shared_ptr<CodeVersion> codeVer = std::make_shared<CodeVersion>(1001, "2019-11-03", "Initial version");
-
- std::cout << "提交初始版本:\n";
- Jungle->commit(codeVer->save());
-
- std::cout << "\n提交一个版本,增加了日志功能:\n";
- codeVer = std::make_shared<CodeVersion>(1002, "2019-11-04", "Add log funciton");
- Jungle->commit(codeVer->save());
-
- std::cout << "\n提交一个版本,增加了Qt图片浏览器:\n";
- codeVer = std::make_shared<CodeVersion>(1003, "2019-11-05", "Add Qt Image Browser");
- Jungle->commit(codeVer->save());
-
- std::cout << "\n查看提交历史\n";
- Jungle->codeLog();
-
- std::cout << "\n回退到上一个版本\n";
- codeVer->restore(Jungle->switchToPointedVersion(1));
-
- std::cout << "\n查看提交历史\n";
- Jungle->codeLog();
-
- return 0;
- }


Strategy.h
- #ifndef __STRATEGY_H__
- #define __STRATEGY_H__
-
- #include <iostream>
-
- // 抽象策略类
- class Strategy{
- public:
- virtual void sort(int arr[], int N) = 0;
- };
-
- // 具体策略:冒泡排序
- class BubbleSort : public Strategy{
- public:
- BubbleSort(){
- std::cout << "冒泡排序\n";
- }
- void sort(int arr[], int N){
- for (int i = 0; i<N; i++)
- {
- for (int j = 0; j<N - i - 1; j++)
- {
- if (arr[j]>arr[j + 1]){
- int tmp = arr[j];
- arr[j] = arr[j + 1];
- arr[j + 1] = tmp;
- }
- }
- }
- }
- };
-
- // 具体策略:选择排序
- class SelectionSort : public Strategy{
- public:
- SelectionSort(){
- std::cout << "选择排序\n";
- }
- void sort(int arr[], int N){
- int i, j, k;
- for (i = 0; i<N; i++)
- {
- k = i;
- for (j = i + 1; j<N; j++)
- {
- if (arr[j] < arr[k]){
- k = j;
- }
- }
- int temp = arr[i];
- arr[i] = arr[k];
- arr[k] = temp;
- }
- }
- };
-
- // 具体策略:插入排序
- class InsertSort :public Strategy
- {
- public:
- InsertSort(){
- printf("插入排序\n");
- }
- void sort(int arr[], int N){
- int i, j;
- for (i = 1; i<N; i++)
- {
- for (j = i - 1; j >= 0; j--)
- {
- if (arr[i]>arr[j]){
- break;
- }
- }
- int temp = arr[i];
- for (int k = i - 1; k > j; k--){
- arr[k + 1] = arr[k];
- }
- arr[j + 1] = temp;
- }
- }
- };
-
- #endif

Context.h
- #include <iostream>
- #include "Context.h"
-
- int main(){
- std::shared_ptr<Context> ctx = std::make_shared<Context>();
- int arr[] = { 10, 23, -1, 0, 300, 87, 28, 77, -32, 2 };
- ctx->setInput(arr, sizeof(arr) / sizeof(int));
- std::cout << "input: ";
- ctx->print();
-
- std::shared_ptr<BubbleSort> bubbleSort = std::make_shared<BubbleSort>();
- ctx->setSortStrategy(bubbleSort);
- ctx->sort();
-
- std::shared_ptr<SelectionSort> selectionSort = std::make_shared<SelectionSort>();
- ctx->setSortStrategy(selectionSort);
- ctx->sort();
-
- std::shared_ptr<InsertSort> insertSort = std::make_shared<InsertSort>();
- ctx->setSortStrategy(insertSort);
- ctx->sort();
-
- return 0;
- }

main.cpp
- #include <iostream>
- #include "Context.h"
-
- int main(){
- std::shared_ptr<Context> ctx = std::make_shared<Context>();
- int arr[] = { 10, 23, -1, 0, 300, 87, 28, 77, -32, 2 };
- ctx->setInput(arr, sizeof(arr) / sizeof(int));
- std::cout << "input: ";
- ctx->print();
-
- std::shared_ptr<BubbleSort> bubbleSort = std::make_shared<BubbleSort>();
- ctx->setSortStrategy(bubbleSort);
- ctx->sort();
-
- std::shared_ptr<SelectionSort> selectionSort = std::make_shared<SelectionSort>();
- ctx->setSortStrategy(selectionSort);
- ctx->sort();
-
- std::shared_ptr<InsertSort> insertSort = std::make_shared<InsertSort>();
- ctx->setSortStrategy(insertSort);
- ctx->sort();
-
- return 0;
- }


FingerprintModule.h
- #ifndef __FINGERPRINTMODULE_H__
- #define __FINGERPRINTMODULE_H__
-
- #include <iostream>
-
- // 基类
- class FingerprintModule{
- public:
- void getImage(){
- std::cout << "采指纹图像\n";
- }
- void output(){
- std::cout << "指纹图像处理完成!\n";
- }
-
- virtual bool isSafeMode() = 0;
- virtual void processImage() = 0;
- // 加解密
- virtual void encrypt() = 0;
- virtual void decrypt() = 0;
-
- // 模板方法
- void algorithm(){
- // 1.采图
- getImage();
- // 2.安全模式下加密和解密
- if (isSafeMode())
- {
- // 2.1. 加密
- encrypt();
- // 2.2. 解密
- decrypt();
- }
- // 3.处理Image
- processImage();
- // 4.处理结果
- output();
- }
- };
-
- // 派生类A
- class FingerprintModuleA : public FingerprintModule{
- public:
- bool isSafeMode(){
- std::cout << "安全模式\n";
- return true;
- }
- void processImage(){
- std::cout << "使用 第一代版本算法 处理指纹图像\n";
- }
- void encrypt(){
- std::cout << "使用RSA密钥加密\n";
- }
- void decrypt(){
- std::cout << "使用RSA密钥解密\n";
- }
- };
-
- // 派生类B
- class FingerprintModuleB : public FingerprintModule{
- public:
- bool isSafeMode(){
- std::cout << "非安全模式\n";
- return false;
- }
- void processImage(){
- std::cout << "使用 第二代版本算法 处理指纹图像\n";
- }
- void encrypt(){}
- void decrypt(){}
- };
-
- // 派生类C
- class FingerprintModuleC : public FingerprintModule{
- public:
- bool isSafeMode(){
- std::cout << "安全模式\n";
- return true;
- }
- void processImage(){
- std::cout << "使用 第一代版本算法 处理指纹图像\n";
- }
- void encrypt(){
- std::cout << "使用DH密钥加密\n";
- }
- void decrypt(){
- std::cout << "使用DH密钥解密\n";
- }
- };
-
- #endif

main.cpp
- #include <iostream>
- #include "FingerprintModule.h"
-
- int main(){
- std::shared_ptr<FingerprintModuleA> fa = std::make_shared<FingerprintModuleA>();
- fa->algorithm();
-
- std::cout << "\n";
- std::shared_ptr<FingerprintModuleB> fb = std::make_shared<FingerprintModuleB>();
- fb->algorithm();
-
- std::cout << "\n";
- std::shared_ptr<FingerprintModuleC> fc = std::make_shared<FingerprintModuleC>();
- fc->algorithm();
-
- return 0;
- }


例1 开源项目GitHub - qicosmos/rest_rpc: modern C++(C++11), simple, easy to use rpc framework
若直接运行server目录下的main.cpp会报错如下:'rest_rpc.hpp' file not found

原因是各头文件的路径是按CMakeLists.txt的include_directories() 来实现的:

所以,通过cmake的方式来组织文件关系, 上面的那个server目录下的main.cpp里的#include <rest_rpc.hpp> 就相当于 #include <../../include/rest_rpc.hpp>。
同理其他的如:

通过cmake执行如下:

【阅读】《Linux高性能服务器编程》——第五章:Linux网络编程基础API - 知乎
【C++】Web服务器项目所用到的函数详解_c++ iovec_半路杀出来的小黑同学的博客-CSDN博客
server.cpp
- #include <iostream>
- #include <sys/socket.h> // socket, bind
- #include <sys/errno.h> // errno
- #include <netinet/in.h> // sockaddr_in
- #include <cstring> // bzero
- #include <signal.h> // signal
- #include <unistd.h> // close
-
- #define BUFFSIZE 2048
- #define DEFAULT_PORT 16555
- #define MAXLINK 2048
-
- int sockfd, connfd; // 定义服务端套接字和客户端套接字
-
- void stopServerRunning(int){
- close(sockfd);
- std::cout << "Close Server\n";
- exit(0);
- }
-
- int main(){
- sockaddr_in servaddr; // 结构体
- char buff[BUFFSIZE]; // 用于收发数据
- // 在Server端和Client端都有一个socket,通过将socket当作文件,可以写入也可读取
- sockfd = socket(AF_INET, SOCK_STREAM, 0);
- if(sockfd == -1){
- std::cout << "Create socket error: " << errno
- << ", :" << strerror(errno) << "\n";
- return -1;
- }
- // void bzero(void* s, int n);//s为内存(字符串)指针,n为需要清零的字节数。
- bzero(&servaddr, sizeof(servaddr));
- // sin_family指代协议族,在socket编程中只能是AF_INET
- servaddr.sin_family = AF_INET;
- // sin_addr存储IP地址,使用in_addr这个数据结构(in_addr.s_addr就是32位IP地址),按照网络字节顺序存储IP地址
- // htonl(Host to Network Long)把本机字节顺序转化为网络字节顺序,htons(Host to Network Short)
- // INADDR_ANY转换过来就是0.0.0.0,泛指本机的意思,也就是表示本机的所有IP
- servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
- servaddr.sin_port = htons(DEFAULT_PORT);
- // bind用来给socket绑定地址信息
- // 通常服务器在启动时会绑定一个总所周知的地址(ip地址+端口号),客户端不用指定系统自动分配,
- // 所以通常服务端在listen之前要调用bind(),而客户端不会调用,在connect()时由系统随机生成一个。
- if(bind(sockfd, (sockaddr*)&servaddr, sizeof(servaddr)) == -1){
- std::cout << "Bind error: " << errno
- << ", :" << strerror(errno) << "\n";
- return -1;
- }
- if(listen(sockfd, MAXLINK) == -1){
- std::cout << "Listen error: " << errno
- << ", :" << strerror(errno) << "\n";
- return -1;
- }
- std::cout << "Listening...\n";
-
- while (true){
- // 这句用于在输入Ctrl+C的时候关闭服务器
- signal(SIGINT, stopServerRunning);
- connfd = accept(sockfd, nullptr, nullptr);
- if(connfd == -1){
- std::cout << "Accept error: " << errno
- << ", :" << strerror(errno) << "\n";
- return -1;
- }
- bzero(buff, BUFFSIZE);
- recv(connfd, buff, BUFFSIZE - 1, 0);
- std::cout << "Recv: " << buff << "\n";
- send(connfd, buff, strlen(buff), 0);
- close(connfd);
- }
-
- return 0;
- }
-
-

client.cpp
- #include <iostream>
- #include <sys/socket.h>
- #include <sys/types.h>
- #include <netinet/in.h> // sockaddr_in
- #include <arpa/inet.h> // inet_pton
- #include <unistd.h> // close
-
- #define BUFFSIZE 2048
- #define SERVER_IP "0.0.0.0" // 指定服务端的IP,记得修改为你的服务端所在的ip
- #define SERVER_PORT 16555 // 指定服务端的port
-
- int main(){
- sockaddr_in servaddr;
- char buff[BUFFSIZE];
- int sockfd = socket(AF_INET, SOCK_STREAM, 0);
- if(sockfd == -1){
- std::cout << "Create socket error: " << errno
- << ", :" << strerror(errno) << "\n";
- return -1;
- }
- bzero(&servaddr, sizeof(servaddr));
- servaddr.sin_family = AF_INET;
- // IP地址转换函数: 将点分十进制的ip地址转化为用于网络传输的数值格式
- inet_pton(AF_INET, SERVER_IP, &servaddr.sin_addr);
- servaddr.sin_port = htons(SERVER_PORT);
- if(connect(sockfd, (sockaddr*)&servaddr, sizeof(servaddr))){
- std::cout << "Connect socket error: " << errno
- << ", :" << strerror(errno) << "\n";
- return -1;
- }
- std::cout << "Please input: \n";
- scanf("%s", buff);
- send(sockfd, buff, strlen(buff), 0);
- bzero(buff, sizeof(buff));
- recv(sockfd, buff, BUFFSIZE - 1, 0);
- std::cout << "Recv: " << buff << "\n";
- close(sockfd);
-
- return 0;
- }

其中解决地址已占用问题:

通信效果如下:


GitHub - yuesong-feng/30dayMakeCppServer: 30天自制C++服务器,包含教程和源代码
server.cpp
- #include <stdio.h>
- #include <sys/socket.h>
- #include <arpa/inet.h>
- #include <string.h>
-
- int main() {
- int sockfd = socket(AF_INET, SOCK_STREAM, 0);
-
- struct sockaddr_in serv_addr;
- bzero(&serv_addr, sizeof(serv_addr));
- serv_addr.sin_family = AF_INET;
- serv_addr.sin_addr.s_addr = inet_addr("127.0.0.1");
- serv_addr.sin_port = htons(8888);
-
- bind(sockfd, (sockaddr*)&serv_addr, sizeof(serv_addr));
-
- listen(sockfd, SOMAXCONN);
-
- struct sockaddr_in clnt_addr;
- socklen_t clnt_addr_len = sizeof(clnt_addr);
- bzero(&clnt_addr, sizeof(clnt_addr));
-
- int clnt_sockfd = accept(sockfd, (sockaddr*)&clnt_addr, &clnt_addr_len);
-
- printf("new client fd %d! IP: %s Port: %d\n", clnt_sockfd, inet_ntoa(clnt_addr.sin_addr), ntohs(clnt_addr.sin_port));
- return 0;
- }

client.cpp
- #include <sys/socket.h>
- #include <arpa/inet.h>
- #include <string.h>
-
- int main() {
- int sockfd = socket(AF_INET, SOCK_STREAM, 0);
-
- struct sockaddr_in serv_addr;
- bzero(&serv_addr, sizeof(serv_addr));
- serv_addr.sin_family = AF_INET;
- serv_addr.sin_addr.s_addr = inet_addr("127.0.0.1");
- serv_addr.sin_port = htons(8888);
-
- //bind(sockfd, (sockaddr*)&serv_addr, sizeof(serv_addr)); 客户端不进行bind操作
-
- connect(sockfd, (sockaddr*)&serv_addr, sizeof(serv_addr));
-
- return 0;
- }



至此,day01的教程已经结束了,进入code/day01文件夹,使用make命令编译,将会得到server和client。输入命令./server开始运行,直到accept函数,程序阻塞、等待客户端连接。然后在一个新终端输入命令./client运行客户端,可以看到服务器接收到了客户端的连接请求,并成功连接。
new client fd 3! IP: 127.0.0.1 Port: 53505
但如果我们先运行客户端、后运行服务器,在客户端一侧无任何区别,却并没有连接服务器成功,因为我们day01的程序没有任何的错误处理。
事实上对于如socket,bind,listen,accept,connect等函数,通过返回值以及errno可以确定程序运行的状态、是否发生错误。在day02的教程中,我们会进一步完善整个服务器,处理所有可能的错误,并实现一个echo服务器(客户端发送给服务器一个字符串,服务器收到后返回相同的内容)。
util.h
- #ifndef UTIL_H
- #define UTIL_H
-
- void errif(bool, const char*);
-
- #endif
util.cpp
- #include "util.h"
- #include <stdio.h>
- #include <stdlib.h>
-
- void errif(bool condition, const char *errmsg){
- if(condition){
- perror(errmsg);
- exit(EXIT_FAILURE);
- }
- }
server.cpp
- #include <stdio.h>
- #include <sys/socket.h>
- #include <arpa/inet.h>
- #include <string.h>
- #include <unistd.h>
- #include "util.h"
-
- int main() {
- int sockfd = socket(AF_INET, SOCK_STREAM, 0);
- errif(sockfd == -1, "socket create error");
-
- struct sockaddr_in serv_addr;
- bzero(&serv_addr, sizeof(serv_addr));
- serv_addr.sin_family = AF_INET;
- serv_addr.sin_addr.s_addr = inet_addr("127.0.0.1");
- serv_addr.sin_port = htons(8888);
-
- errif(bind(sockfd, (sockaddr*)&serv_addr, sizeof(serv_addr)) == -1, "socket bind error");
-
- errif(listen(sockfd, SOMAXCONN) == -1, "socket listen error");
-
- struct sockaddr_in clnt_addr;
- socklen_t clnt_addr_len = sizeof(clnt_addr);
- bzero(&clnt_addr, sizeof(clnt_addr));
-
- int clnt_sockfd = accept(sockfd, (sockaddr*)&clnt_addr, &clnt_addr_len);
- errif(clnt_sockfd == -1, "socket accept error");
-
- printf("new client fd %d! IP: %s Port: %d\n", clnt_sockfd, inet_ntoa(clnt_addr.sin_addr), ntohs(clnt_addr.sin_port));
- while (true) {
- char buf[1024];
- bzero(&buf, sizeof(buf));
- ssize_t read_bytes = read(clnt_sockfd, buf, sizeof(buf));
- if(read_bytes > 0){
- printf("message from client fd %d: %s\n", clnt_sockfd, buf);
- write(clnt_sockfd, buf, sizeof(buf));
- } else if(read_bytes == 0){
- printf("client fd %d disconnected\n", clnt_sockfd);
- close(clnt_sockfd);
- break;
- } else if(read_bytes == -1){
- close(clnt_sockfd);
- errif(true, "socket read error");
- }
- }
- close(sockfd);
- return 0;
- }

client.cpp
- #include <iostream>
- #include <sys/socket.h>
- #include <arpa/inet.h>
- #include <string.h>
- #include <unistd.h>
- #include "util.h"
-
-
- int main() {
- int sockfd = socket(AF_INET, SOCK_STREAM, 0);
- errif(sockfd == -1, "socket create error");
-
- struct sockaddr_in serv_addr;
- bzero(&serv_addr, sizeof(serv_addr));
- serv_addr.sin_family = AF_INET;
- serv_addr.sin_addr.s_addr = inet_addr("127.0.0.1");
- serv_addr.sin_port = htons(8888);
-
- errif(connect(sockfd, (sockaddr*)&serv_addr, sizeof(serv_addr)) == -1, "socket connect error");
-
- while(true){
- char buf[1024];
- bzero(&buf, sizeof(buf));
- scanf("%s", buf);
- ssize_t write_bytes = write(sockfd, buf, sizeof(buf));
- if(write_bytes == -1){
- printf("socket already disconnected, can't write any more!\n");
- break;
- }
- bzero(&buf, sizeof(buf));
- ssize_t read_bytes = read(sockfd, buf, sizeof(buf));
- if(read_bytes > 0){
- printf("message from server: %s\n", buf);
- }else if(read_bytes == 0){
- printf("server socket disconnected!\n");
- break;
- }else if(read_bytes == -1){
- close(sockfd);
- errif(true, "socket read error");
- }
- }
- close(sockfd);
- return 0;
- }



至此,我们已经完整地开发了一个echo服务器,并且有最基本的错误处理!
但现在,我们的服务器只能处理一个客户端,我们可以试试两个客户端同时连接服务器,看程序将会如何运行。在day03的教程里,我们将会讲解Linux系统高并发的基石--epoll,并编程实现一个可以支持无数客户端同时连接的echo服务器!
server.cpp
- #include <stdio.h>
- #include <sys/socket.h>
- #include <arpa/inet.h>
- #include <string.h>
- #include <unistd.h>
- #include <fcntl.h>
- #include <sys/epoll.h>
- #include <errno.h>
- #include "util.h"
-
- #define MAX_EVENTS 1024
- #define READ_BUFFER 1024
-
- // 设置非阻塞
- void setnonblocking(int fd){
- // 设置文件的flags: fcntl(fd,F_SETFL,flags);
- fcntl(fd, F_SETFL, fcntl(fd, F_GETFL) | O_NONBLOCK);
- }
-
- int main(){
- int sockfd = socket(AF_INET, SOCK_STREAM, 0);
- errif(sockfd == -1, "socket create error");
-
- struct sockaddr_in serv_addr;
- bzero(&serv_addr, sizeof(serv_addr));
- serv_addr.sin_family = AF_INET;
- serv_addr.sin_addr.s_addr = inet_addr("127.0.0.1");
- serv_addr.sin_port = htons(8888);
-
- errif(bind(sockfd, (sockaddr*)&serv_addr, sizeof(serv_addr)) == -1, "socket bind error");
-
- errif(listen(sockfd, SOMAXCONN) == -1, "socket listen error");
-
- // 创建一个epoll文件描述符并返回,失败则返回-1
- int epfd = epoll_create1(0);
- errif(epfd == -1, "epoll create error");
-
- struct epoll_event events[MAX_EVENTS], ev;
- bzero(&events, sizeof(events));
- bzero(&ev, sizeof(ev));
- ev.data.fd = sockfd; // 该IO口为服务器socket fd(文件描述符)
- // EPOLLIN:LT模式,EPOLLET:ET模式
- ev.events = EPOLLIN; // 服务端最好不要用ET模式
- setnonblocking(sockfd);
- // 将服务器socket fd添加到epoll
- epoll_ctl(epfd, EPOLL_CTL_ADD, sockfd, &ev);
-
- while (1){
- // epoll_wait获取有事件发生的fd
- // 最大等待时间,设置为-1表示一直等待
- int nfds = epoll_wait(epfd, events, MAX_EVENTS, -1); // 有nfds个fd发生事件
- errif(nfds == -1, "epoll wait error");
-
- for(int i = 0; i < nfds; ++i){
- if(events[i].data.fd == sockfd){ // 发生事件的fd是服务器socket fd,表示有新客户端连接
-
- struct sockaddr_in clnt_addr;
- bzero(&clnt_addr, sizeof(clnt_addr));
- socklen_t clnt_addr_len = sizeof(clnt_addr);
-
- int clnt_sockfd = accept(sockfd, (sockaddr*)&clnt_addr, &clnt_addr_len);
- errif(clnt_sockfd == -1, "socket accept error");
- printf("new client fd %d! IP: %s Port: %d\n", clnt_sockfd, inet_ntoa(clnt_addr.sin_addr), ntohs(clnt_addr.sin_port));
-
- bzero(&ev, sizeof(ev));
- ev.data.fd = clnt_sockfd;
- ev.events = EPOLLIN | EPOLLET; // 对于客户端连接,使用ET模式,可以让epoll更加高效,支持更多并发
- setnonblocking(clnt_sockfd); // ET需要搭配非阻塞式socket使用
- epoll_ctl(epfd, EPOLL_CTL_ADD, clnt_sockfd, &ev);
- }else if (events[i].events & EPOLLIN){ // 发生事件的是客户端,并且是可读事件(EPOLLIN)
-
- char buf[READ_BUFFER];
- while(true){ //由于使用非阻塞IO,读取客户端buffer,一次读取buf大小数据,直到全部读取完毕
- bzero(&buf, sizeof(buf));
- ssize_t bytes_read = read(events[i].data.fd, buf, sizeof(buf));
-
- if(bytes_read > 0){
-
- // 保存读取到的bytes_read大小的数据
- printf("message from client fd %d: %s\n", events[i].data.fd, buf);
- write(events[i].data.fd, buf, sizeof(buf));
- }else if(bytes_read == -1 && errno == EINTR){ // 客户端正常中断、继续读取
-
- printf("continue reading");
- continue;
- }else if(bytes_read == -1 && ((errno == EAGAIN) || (errno == EWOULDBLOCK))){ // 非阻塞IO,这个条件表示数据全部读取完毕
-
- printf("finish reading once, errno: %d\n", errno);
- break;
- }else if(bytes_read == 0){ // EOF,客户端断开连接
-
- printf("EOF, client fd %d disconnected\n", events[i].data.fd);
- close(events[i].data.fd); // 关闭socket会自动将文件描述符从epoll树上移除
- break;
- }
- }
- }else{ //其他事件,之后的版本实现
- printf("something else happened\n");
- }
- }
- }
- close(sockfd);
-
- return 0;
- }

client.cpp
- #include <iostream>
- #include <sys/socket.h>
- #include <arpa/inet.h>
- #include <string.h>
- #include <unistd.h>
- #include "util.h"
-
- #define BUFFER_SIZE 1024
-
- int main(){
- int sockfd = socket(AF_INET, SOCK_STREAM, 0);
- errif(sockfd == -1, "socket create error");
-
- struct sockaddr_in serv_addr;
- bzero(&serv_addr, sizeof(serv_addr));
- serv_addr.sin_family = AF_INET;
- serv_addr.sin_addr.s_addr = inet_addr("127.0.0.1");
- serv_addr.sin_port = htons(8888);
-
- errif(connect(sockfd, (sockaddr*)&serv_addr, sizeof(serv_addr)) == -1, "socket connect error");
-
- while (1){
- char buf[BUFFER_SIZE]; //在这个版本,buf大小必须大于或等于服务器端buf大小,不然会出错,想想为什么?
- bzero(&buf, sizeof(buf));
- scanf("%s", buf);
- ssize_t write_bytes = write(sockfd, buf, sizeof(buf));
- if(write_bytes == -1){
- printf("socket already disconnected, can't write any more!\n");
- break;
- }
-
- bzero(&buf, sizeof(buf));
- ssize_t read_bytes = read(sockfd, buf, sizeof(buf));
- if(read_bytes > 0){
- printf("message from server: %s\n", buf);
- }else if(read_bytes == 0){
- printf("server socket disconnected!\n");
- break;
- }else if(read_bytes == -1){
- close(sockfd);
- errif(true, "socket read error");
- }
- }
- close(sockfd);
-
- return 0;
- }


InetAddress.h
- #pragma once
-
- #include <iostream>
- #include <arpa/inet.h>
-
- class InetAddress{
- public:
- InetAddress();
- InetAddress(std::string ip, uint16_t port);
-
- struct sockaddr_in getAddr(){
- return addr;
- }
-
- socklen_t getAddrLen(){
- return addr_len;
- }
-
- private:
- struct sockaddr_in addr;
- socklen_t addr_len;
- };

InetAddress.cpp
- #include <iostream>
- #include<string.h>
-
- #include "InetAddress.h"
-
- InetAddress::InetAddress() : addr_len(sizeof(addr)){
- bzero(&addr, sizeof(addr));
- }
-
- InetAddress::InetAddress(std::string ip, uint16_t port) : addr_len(sizeof(addr)){
- bzero(&addr, sizeof(addr));
- addr.sin_family = AF_INET;
- addr.sin_addr.s_addr = inet_addr(ip.c_str());
- addr.sin_port = htons(port);
- }
Socket.h
- #pragma once
-
- #include <iostream>
- #include <tr1/memory>
-
- #include "InetAddress.h"
-
- class Socket{
- public:
- Socket();
- Socket(int);
- ~Socket();
-
- void bind(InetAddress*);
- void listen();
- void setnonblocking();
-
- int accept(InetAddress*);
-
- int getFd();
-
- private:
- int fd; // 文件描述符
- };

Socket.cpp
- #include "Socket.h"
- #include "InetAddress.h"
- #include "util.h"
- #include <unistd.h>
- #include <fcntl.h>
- #include <sys/socket.h>
- #include <iostream>
- #include <tr1/memory>
-
- Socket::Socket() : fd(-1){
- fd = socket(AF_INET, SOCK_STREAM, 0);
- errif(fd == -1, "socket create error");
- }
-
- Socket::Socket(int fd_) : fd(fd_){
- errif(fd == -1, "socket create error");
- }
-
- Socket::~Socket(){
- if(fd != -1){
- close(fd);
- fd = -1;
- }
- }
-
- void Socket::bind(InetAddress *addr){
- struct sockaddr_in addrTmp = addr->getAddr();
- socklen_t addrLen = addr->getAddrLen();
- errif(::bind(fd, (sockaddr*)&addrTmp, addrLen) == -1, "socket bind error");
- }
-
- void Socket::listen(){
- errif(::listen(fd, SOMAXCONN) == -1, "socket listen error");
- }
-
- void Socket::setnonblocking(){
- fcntl(fd, F_SETFL, fcntl(fd, F_GETFL) | O_NONBLOCK);
- }
-
- int Socket::accept(InetAddress *addr){
- struct sockaddr_in addrTmp = addr->getAddr();
- socklen_t addrLen = addr->getAddrLen();
- int clnt_sockfd = ::accept(fd, (sockaddr*)&addrTmp, &addrLen);
- errif(clnt_sockfd == -1, "socket accept error");
- return clnt_sockfd;
- }
-
- int Socket::getFd(){
- return fd;
- }

Epoll.h
- #pragma once
-
- #include <sys/epoll.h>
- #include <iostream>
- #include <vector>
-
- class Epoll{
- public:
- Epoll();
- ~Epoll();
- void addFd(int fd, uint32_t op);
- std::vector<epoll_event> poll(int timeout = -1);
-
- private:
- int epfd;
- epoll_event* events;
- };

Epoll.cpp
- #include "Epoll.h"
- #include "util.h"
- #include <unistd.h>
- #include <string.h>
- #include <iostream>
-
- #define MAX_EVENTS 1000
-
- Epoll::Epoll() : epfd(-1), events(nullptr){
- epfd = epoll_create1(0);
- errif(epfd == -1, "epoll create error");
- events = new epoll_event[MAX_EVENTS];
- bzero(events, sizeof(*events) * MAX_EVENTS);
- }
-
- Epoll::~Epoll(){
- if(epfd != -1){
- close(epfd);
- epfd = -1;
- }
-
- delete[] events; // 防止内存泄漏
- }
-
- void Epoll::addFd(int fd, uint32_t op){
- struct epoll_event ev;
- bzero(&ev, sizeof(ev));
- ev.data.fd = fd;
- ev.events = op;
- errif(epoll_ctl(epfd, EPOLL_CTL_ADD, fd, &ev) == -1, "epoll add event error");
- }
-
- std::vector<epoll_event> Epoll::poll(int timeout){
- std::vector<epoll_event> activeEvents;
- int nfds = epoll_wait(epfd, events, MAX_EVENTS, timeout);
- errif(nfds == -1, "epoll wait error");
- for(int i = 0; i < nfds; ++i){
- activeEvents.push_back(events[i]);
- }
-
- return activeEvents;
- }

server.cpp
- #include <stdio.h>
- #include <string.h>
- #include <unistd.h>
- #include <fcntl.h>
- #include <errno.h>
- #include <vector>
- #include "util.h"
- #include "Epoll.h"
- #include "InetAddress.h"
- #include "Socket.h"
- #include <iostream>
-
- #define MAX_EVENTS 1024
- #define READ_BUFFER 1024
-
- void setnonblocking(int fd){
- fcntl(fd, F_SETFL, fcntl(fd, F_GETFL) | O_NONBLOCK);
- }
-
- void handleReadEvent(int);
-
- int main() {
- Socket *serv_sock = new Socket();
- InetAddress *serv_addr = new InetAddress("127.0.0.1", 8888);
- serv_sock->bind(serv_addr);
- serv_sock->listen();
- Epoll *ep = new Epoll();
- serv_sock->setnonblocking();
- ep->addFd(serv_sock->getFd(), EPOLLIN | EPOLLET);
-
- while(true){
- std::vector<epoll_event> events = ep->poll();
- int nfds = events.size();
- for(int i = 0; i < nfds; ++i){
- if(events[i].data.fd == serv_sock->getFd()){ // 新客户端连接
- // new InetAddress() 位置只能在这里!
- InetAddress *clnt_addr = new InetAddress();
- Socket *clnt_sock = new Socket(serv_sock->accept(clnt_addr));
- printf("new client fd %d! IP: %s Port: %d\n", clnt_sock->getFd(),
- inet_ntoa(clnt_addr->getAddr().sin_addr), ntohs(clnt_addr->getAddr().sin_port));
- clnt_sock->setnonblocking();
- ep->addFd(clnt_sock->getFd(), EPOLLIN | EPOLLET);
- } else if(events[i].events & EPOLLIN){ // 可读事件
- handleReadEvent(events[i].data.fd);
- } else{ // 其他事件,之后的版本实现
- printf("something else happened\n");
- }
- }
- }
- delete serv_sock;
- delete serv_addr;
- delete ep;
-
- return 0;
- }
-
- void handleReadEvent(int sockfd){
- char buf[READ_BUFFER];
- while (1){ // 由于使用非阻塞IO,读取客户端buffer,一次读取buf大小数据,直到全部读取完毕
- bzero(&buf, sizeof(buf));
- ssize_t bytes_read = read(sockfd, buf, sizeof(buf));
- if(bytes_read > 0){
- printf("message from client fd %d: %s\n", sockfd, buf);
- write(sockfd, buf, sizeof(buf));
- } else if(bytes_read == -1 && errno == EINTR){ // 客户端正常中断、继续读取
- printf("continue reading");
- continue;
- } else if(bytes_read == -1 && ((errno == EAGAIN) || (errno == EWOULDBLOCK))){ // 非阻塞IO,这个条件表示数据全部读取完毕
- printf("finish reading once, errno: %d\n", errno);
- break;
- } else if(bytes_read == 0){ // EOF,客户端断开连接
- printf("EOF, client fd %d disconnected\n", sockfd);
- close(sockfd); // 关闭socket会自动将文件描述符从epoll树上移除
- break;
- }
- }
- }

client.cpp
- #include <iostream>
- #include <sys/socket.h>
- #include <arpa/inet.h>
- #include <string.h>
- #include <unistd.h>
- #include "util.h"
-
- #define BUFFER_SIZE 1024
-
- int main(){
- int sockfd = socket(AF_INET, SOCK_STREAM, 0);
- errif(sockfd == -1, "socket create error");
-
- struct sockaddr_in serv_addr;
- bzero(&serv_addr, sizeof(serv_addr));
- serv_addr.sin_family = AF_INET;
- serv_addr.sin_addr.s_addr = inet_addr("127.0.0.1");
- serv_addr.sin_port = htons(8888);
-
- errif(connect(sockfd, (sockaddr*)&serv_addr, sizeof(serv_addr)) == -1, "socket connect error");
-
- while (1){
- char buf[BUFFER_SIZE]; //在这个版本,buf大小必须大于或等于服务器端buf大小,不然会出错,想想为什么?
- bzero(&buf, sizeof(buf));
- scanf("%s", buf);
- ssize_t write_bytes = write(sockfd, buf, sizeof(buf));
- if(write_bytes == -1){
- printf("socket already disconnected, can't write any more!\n");
- break;
- }
-
- bzero(&buf, sizeof(buf));
- ssize_t read_bytes = read(sockfd, buf, sizeof(buf));
- if(read_bytes > 0){
- printf("message from server: %s\n", buf);
- }else if(read_bytes == 0){
- printf("server socket disconnected!\n");
- break;
- }else if(read_bytes == -1){
- close(sockfd);
- errif(true, "socket read error");
- }
- }
- close(sockfd);
-
- return 0;
- }

- g++ util.cpp client.cpp -o client && \
- g++ util.cpp server.cpp Epoll.cpp InetAddress.cpp Socket.cpp -o server

至此,我们已经完整地开发了一个echo服务器,并且引入面向对象编程的思想,初步封装了Socket、InetAddress和Epoll,大大精简了主程序,隐藏了底层语言实现细节、增加了可读性。
https://www.cnblogs.com/shuqin/p/12214439.html
https://www.cnblogs.com/fortunely/p/17388565.html
简介:
文件结构:

代码逻辑结构:
有几个比较重要的文件:
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。