常用设计模式-广撒网不如慢慢专精

文章目录


其实地上本没有路,走的人多了,也便成了路

1 什么是设计模式

1.1 历史

模式是指,在某一特定的场景下某类问题的解决方案。
模式最早是使用在建筑设计上的一个词汇。在经过无数次失败建筑后,人们总结出了一套设计方案,例如,坐南朝北可以采光,起脊可以排水,地基可以防风等等,这一些列的总结,就形成了房屋设计的范式。
”样式雷”就是中国建筑集大成者,故就是样式雷的里程碑作品。
范式再经过,整理抽象提升,就成了,今天所谓的设计模式

每一个模式,通过一种让你可以无数次使用这一解决方案,而不必再次重复同样的工作的方式,描述一个在我们的环境中重复出现的问题,并描述了该问题解决方案的核心

1.2 如何陈述模式

用量化的方案来看待设计模式,至少应该包含以下四个点:

  1. 模式的名称
  2. 模式的目的,它要解决的问题
  3. 我们如何实现
  4. 为了实现它,我们必须考虑的限制和约束

1.3 学习模式的意义

  1. 复用解决方案——通过复用己经建立的设计,而无重复设计,避免绕弯路,如果说我看的远,那是因为,我站在巨人的肩上。
  2. 交流通常术语——交流与协作都需要一个共同的词汇基础,一个对问题解决方字案的共同观点,设计模式在项目的分析和设计阶段提供了一个通用的参考点。
  3. 更高级别视角——在没有开始真正的编码前,站在一个更高的层次上来高设计,避免提前陷入代码的泥淖。

1.4 设计模式学习的建议

1.4.1 GOF的建议

  • 针对接口编程
  • 优先使用组合,而不是继承
  • 找到并封装变化点

2 设计模式的原则

所有的设计原则,本质都只有一个目标,就是软件行业的最高设计标准,高内聚,低耦合

2.1 单一职责原则(Single Responsibility Principle - SRP)

2.1.1 定义

不要存在多于一个导致类变更的原因。通俗的说,即一个类只负责一项职责

2.1.2 问题由来

类 T 负责两个不同的职责:职责 P1,职责 P2。当由于职责 P1 需求发生改变而需要修改类 T 时,有可能会导致原本运行正常的职责 P2 功能发生故障。

2.1.3 解决方案

将类 T 分成两个不同的类来实现。比如 C 语言中会将头文件分类 string.h stdio.h,Qt 中 QLable QButton 等。C++中会有 string fstream 类,就是单一原则的体现/

2.2 开闭原则(Open Closed Principle - OCP)

2.2.1 定义

一个软件实体,如类、模块和函数应该对扩展开放,对修改关闭。

2.2.2 问题由来

在软件的生命周期内,因为变化、升级和维护等原因需要对软件原有代码进行修改时,可能会给旧代码中引入错误,也可能会使我们不得不对整个功能进行重构,并且需要原有代码经过重新测试。

2.2.3 解决方案

当软件需要变化时,尽量通过扩展软件实体的行为来实现变化,而不是通过修改已有的代码来实现变化。

2.3 依赖倒置原则(Dependence Inversion Principle - DIP)

2.3.1 定义

高层模块不应该依赖低层模块,二者都应该依赖其抽象;抽象不应该依赖细节;细节应该依赖抽象

2.3.2 问题由来

类 A 直接依赖类 B,假如要将类 A 改为依赖类 C,则必须通过修改类 A 的代码来达成。这种场景下,类 A 一般是高层模块,负责复杂的业务逻辑;类 B 和类 C 是低层模块,负责基本的原子操作;假如修改类 A,会给程序带来不必要的风险。
在这里插入图片描述

2.3.3 解决方案

将类 A 修改为依赖接口 I,类 B 和类 C 各自实现接口 I,类 A 通过接口 I 间接与类 B或者类 C 发生联系,则会大大降低修改类 A 的几率。
在这里插入图片描述

2.3.4 实例

class IReader {
public:
    virtual string getContents() = 0;
};

class Book: public IReader {
public:
    string getContents()
    {
        return "从前有座山,山里有座庙,庙里有一个老和尚和一个小和尚";
    }
};

class Paper: public IReader {
public:
    string getContents()
    {
        return "今日新闻XXXXXXXXXXXXXXXXXX";
    }
};

class Mother {
public:
    void tellStory(IReader* ir)
    {
        cout << ir->getContents() << endl;
    }
};

2.4 接口隔离原则(Interface Segregation Principle - ISP)

2.4.1 定义

客户端不应该依赖它不需要的接口;一个类对另一个类的依赖应该建立在最小的接口上。

2.4.2 问题由来

类 A 通过接口 I 依赖类 B,类 C 通过接口 I 依赖类 D,如果接口 I 对于类 A 和类 B来说不是最小接口,则类 B 和类 D 必须去实现他们不需要的方法。
在这里插入图片描述

2.4.3 解决方案

将臃肿的接口 I 拆分为独立的几个接口,类 A 和类 C 分别与他们需要的接口建立依赖关系。也就是采用接口隔离原则。
在这里插入图片描述

2.4.4 实例

class IReader {
public:
    virtual string getContents() = 0;
};

class Play {
public:
    virtual void playBall() = 0;
};

class Book: public IReader {
public:
    string getContents()
    {
        return "从前有座山,山里有座庙,庙里有一个老和尚和一个小和尚";
    }
};

class Paper: public IReader {
public:
    string getContents()
    {
        return "今日新闻XXXXXXXXXXXXXXXXXX";
    }
};

class Mother {
public:
    void tellStory(IReader* ir)
    {
        cout << ir->getContents() << endl;
    }
};

class FootBall :public Play {
public:
    void playBall()
    {
        cout << "play football..." << endl;
    }

};

class BasketBall :public Play {
public:
    void playBall()
    {
        cout << "play basketball..." << endl;
    }

};

class Father {
public:
    void play(Play * pl)
    {
        pl->playBall();
    }
};

2.5 里氏替换原则(Liskov Substitution Principle - LSP)

2.5.1 定义

如果对每一个类型为 T1 的对象 o1,都有类型为 T2 的对象 o2,使得以 T1 定义的所有程序 P 在所有的对象 o1 都代换成 o2 时,程序 P 的行为没有发生变化,那么类型 T2 是类型 T1 的子类型。
所有引用基类的地方必须能透明地使用其子类的对象。

2.5.2 问题由来

当使用继承时,遵循里氏替换原则。类 B 继承类 A 时,除添加新的方法完成新增功能 P2 外,尽量不要 shadow(遮盖)父类 A 的方法。
继承作为面向对象三大特性之一,在给程序设计带来巨大便利的同时,也带来了弊端。比如使用继承会给程序带来侵入性,程序的可移植性降低,增加了对象间的耦合性,如果一个类被其他的类所继承,则当这个类需要修改时,必须考虑到所有的子类,并且父类修改后,所有涉及到子类的功能都有可能会产生故障。

2.5.3 解决方案

里氏替换原则通俗的来讲就是:子类可以扩展父类的功能,但不能改变父类原有的功能。它包含以下 2 层含义:

  • 子类中可以增加自己特有的方法。
  • 子类可以实现父类的抽象方法, 但不能覆盖父类的非抽象方法

3 UML 类图关系

3.1 类图关系的由来

3.1.1 面向过程

3.1.2 面向对象

在这里插入图片描述

3.2 类间关系综述

面向过程的语言,本质就是函数间的调用关系,但是面向对象以后,函数和数据被封装到类以后,对象的函数间发生关系,此时的研究方向就变成了,类与类之间的关系。

3.2.1 纵向

  • 继承父类
  • 实现父类接口
class Base{};
class Derived:public Bse{};

3.2.2 横向

  • 类成员对象,引用,指针。
  • 类中成员函数的对象,引用,指针。
class A {};
class B {
public:
	void dis(A a, A &ra, A* pa){};
private:
	A a;
	A &ra;
	A *pa;
}

3.2.3 关系规范

  • 泛化
  • 实现
  • 关联
    – 组合关联 Contain-a
    – 聚合关联 Has-a
    – 普通关联 A-A
    – 依赖关联 Usa-a

4 类类关系的正解

4.1 Generalization(泛化)

4.1.1 泛化关系

是一种继承关系, 表示一般与特殊的关系, 它指定了子类如何特化父类的所有特征和行为。

4.1.2 箭头指向

带三角箭头的实现,箭头指向父类。

4.1.3 类关系图

在这里插入图片描述

4.2 实现(Interface Realization)

4.2.1 实现关系

是一种类与接口的关系,表示类是接口所有特征和行为的实现。

4.2.2 箭头指向

带三角箭头的虚线,箭头指向接口。

4.2.3 类图关系

在这里插入图片描述

4.3 关联(Composition)

4.3.1 组合关系

组合也是关联关系的一种特例,他体现的是一种 contains-a 的关系,这种关系比聚合更强,也称为强聚合;他同样体现整体与部分间的关系,但此时整体与部分是不可分的,它要求代表整体的对象负责代表部分的对象的生命周期整体的生命周期结束也就意味着部分的生命周期结束。比如你和你的大脑。
表现在代码层面,和关联关系是一致的,只能从语义级别来区分;

4.3.2 箭头及指向

带实心菱形的实线菱形指向整体

4.3.3 类关系图

在这里插入图片描述

4.4 聚合关联(Aggregation)

4.4.1 聚合关系

聚合是关联关系的一种特例,他体现的是整体与部分、拥有的关系,即 has-a 的关系,此时整体与部分之间是可分离的,他们可以具有各自的生命周期,部分可以属于多个整体对象,也可以为多个整体对象共享。比如公司与员工的关系等。
表现在代码层面,和关联关系是一致的,只能从语义级别来区分。

4.4.2 箭头及指向

空心菱形实心线菱形指向整体

4.4.3 类图关系

在这里插入图片描述

4.4.4 组合和聚合的区别

大雁和雁群,是一种弱的关联关系,雁群拥有大雁,大雁是雁群的一部分,但是也可以独立的存在,可以不与雁群有相同的生命周期。而大雁有两个翅膀,翅膀和大雁是部分和整体间的关系,并且有着相同的生命周期。
在这里插入图片描述

4.4.5 实例

class Wing {
public:
    Wing()
    {
        cout << "Wing Create..." << endl;
    }
    ~Wing()
    {
        cout << "Wing Destory..." << endl;
    }

};

class Bird {
public:
    Bird()
    {
        left = new Wing;
        right = new Wing;
        cout << "Bird Create..." << endl;
    }

    ~Bird()
    {
        delete left;
        delete right;
        cout << "Bird Destory..." << endl;
    }
private:
    Wing* left;
    Wing* right;
};

class Flork {
public:
    void flyIN(Bird * b)
    {
        vb.push_back(b);
    }

    Bird* flyOUT()
    {
        Bird* b = vb.back();
        vb.pop_back();
        return b;
    }

private:
    vector<Bird *> vb;
};

4.5 普通关联(Association)

4.5.1 关联关系

是一种拥有的关系, 它使一个类知道另一个类的属性和方法,强调的是一种 A-A 的关系;关联可以是双向的,也可以是单向的。双向的关联可以有两个箭头或者没有箭头,单向的关联有一个箭头。
在代码层面,通常体现为成员变量的关系。

4.5.2 箭头就及指向

普通箭头的实心线指向被拥有者

4.5.3 类图关系

在这里插入图片描述

4.5.4 实例

//普通关联
class Student;

class Teacher {
public:
    void addStudent(Student* s)
    {
        vs.push_back(s);
    }
private:
    vector<Student*> vs;
};

class Student {
public:
    void addTeachr(Teacher* t)
    {
        vt.push_back(t);
    }

private:
    vector<Teacher*> vt;
};

4.6 依赖关联(Dependency)

4.6.1 依赖关系

是一种使用的关系,即一个类的实现需要另一个类的协助,所以要尽量不使用双向的互相依赖
比如某人要过河,需要借用一条船,此时人与船之间的关系就是依赖;表现在代码层面,为类 B 作为参数被类 A 在某个 method 方法中使用。
局部变量、方法的参数或者对静态方法的调用

4.6.2 箭头及指向

带箭头的虚线,指向被使用者

4.6.3 类图关系

在这里插入图片描述

4.6.4 实例

//依赖关联
class Tool {
public:
    virtual void useToll() = 0;
};

class Boat: public Tool {
public:
    void useToll()
    {
        cout << "乘船出行...." << endl;
    }
};

class Plane : public Tool {
public:
    void useToll()
    {
        cout << "乘飞机出行...." << endl;
    }
};

class Person {
public:
    void travel(Tool* t)
    {
        t->useToll();
    }
};

5 单例模式(Singleton)

5.1 定义

Ensure a class has only one instance, and provide a global point of access to it.(确保某一个类只有一个实例而且自行实例化并向整个系统提供这个实例)。
在这里插入图片描述

5.2 类图关系

在这里插入图片描述

5.3 实例讲解

5.3.1 实现

//传统的方式已经被private,不可用。
class Singleton {
public:
    static Singleton* getInstance()
    {
        if (_instance == nullptr)
            _instance = new Singleton;//若是空,创建
        return _instance;//否则直接返回
    }

private:
    static Singleton* _instance;
    Singleton()
    {
        cout << "Singleton()..." << endl;
    }

    Singleton(const Singleton& another)
    {

    }

    Singleton& operator=(const Singleton& another)
    {

    }

    ~Singleton()
    {
        cout << "~Singleton()..." << endl;
    }
};

Singleton* Singleton::_instance = nullptr;

5.4 拓展实战

5.4.1 全局配置文件

5.4.1.1 conf.h

6 观察者模式(Observer)

6.1 定义

Define a one-to-many dependency between objects so that when one object changes state,all its dependents are notified and updated automatically.(定义对象间一种一对多的依赖关系, 使得每当一个对象改变状态, 则所有依赖于它的对象都会得到通知并被自动更新)。
观察者处于被动地位,被观察者处于主动地位。这种交互也称为发布-订阅 (publish-subscribe)。
在这里插入图片描述
比如,在如下的设计中,就需要用到观察者模式。在这里插入图片描述

6.2 类图关系

在这里插入图片描述

6.3 实例

7 策略模式(Strategy)

7.1 定义

Define a family of algorithms,encapsulate each one,and make them interchangeable.(定义一组算法, 将每个算法都封装起来, 并且使它们之间可以互换)。
在这里插入图片描述

7.2 类图关系

在这里插入图片描述

7.3 示例

7.3.1 应用场景

比如在游戏中,我们在操作相同的情况下,拿起不同的武器,此时产生的效果是不同的。如,招式,伤害,特效,攻击范围。在CS中,可以切换匕首,也可以拿起各种枪械。然后他们的操作都只有鼠标的左右键。这时候,策略模式就派上用场了。

7.3.2 实现

class Weapon {
public:
    virtual void use() = 0;
};

class Gun: public Weapon
{
public:
    void use()
    {
        cout << "用枪攻击敌人。。。" << endl;
    }

};

class Knife: public Weapon {
public:
    void use()
    {
        cout << "用刀攻击敌人。。。" << endl;
    }
};

class Sprite {
public:
    Sprite(Weapon* wp = new Knife)
    {
        wp_ = wp;
    }
    void setWeapon(Weapon* wp)
    {
        wp_ = wp;
    }
    void Attack()
    {
        wp_->use();
    }
private:
    Weapon* wp_;
};

int main(int argc, char** argv)
{
    Sprite sp;
    sp.Attack();
    Knife k;
    Gun g;
    sp.setWeapon(&k);
    sp.Attack();
    sp.setWeapon(&g);
    sp.Attack();

    system("pause");
    return 0;
}

8 代理模式(Proxy)

8.1 定义

Provide a surrogate or placeholder for another object to control access to it.(为其他对象提供一种代理以控制对这个对象的访问)。
对一个对象进行访问控制的一个原因是为了只有在我们确实需要这个对象时才对它进行创建和初始化。
在这里插入图片描述

8.2 类图关系

在这里插入图片描述
在这里插入图片描述

8.3 实例讲

8.3.1 虚代理

考虑一个可以在文档中嵌入图形对象的文档编辑器。有些图形对象的创建开销很大。但是打开文档必须很迅速,因此我们在打开文档时应避免一次性创建所有开销很大的对象。这里就可以运用代理模式,在打开文档时,并不打开图形对象,而是打开图形对象的代理以替代真实的图形。待到真正需要打开图形时,仍由代理负责打开。

8.3.1.1 实现
class Text {
public:
    void showText()
    {
        cout << "好诗,好诗,好诗 好诗,好诗,好诗 好诗,好诗,好诗" << endl;
        cout << "好诗,好诗,好诗 好诗,好诗,好诗 好诗,好诗,好诗" << endl;
        cout << "好诗,好诗,好诗 好诗,好诗,好诗 好诗,好诗,好诗" << endl;
        cout << "好诗,好诗,好诗 好诗,好诗,好诗 好诗,好诗,好诗" << endl;
    }
};

class ImageSubject {
public:
    virtual void showImage() = 0;
};

class BigImage:public ImageSubject {
public:
    BigImage()
    {
        Sleep(10000);
        cout << "big image 加载完毕" << endl;
    }

    void showImage()
    {
        cout << "清明上河图.png" << endl;
    }
};

class ImageProxy:public ImageSubject {
public:
    ImageProxy():pb_(nullptr) //用nullptr初始化图片代理
    {
    }
    void showImage()
    {
        if (pb_ == nullptr)
            pb_ = new BigImage;

        pb_->showImage();
    }

private:
    BigImage* pb_;
};

class Doc {
public:
    Doc()
    {
        t_ = new Text;
        b_ = new ImageProxy;
    }
    void show()
    {
        t_->showText();
        b_->showImage();
    }
private:
    Text* t_;
    ImageProxy* b_;
};

8.3.2 智能代理

//智能代理
class A {
public:
    A()
    {
        cout << "A()" << endl;
    }

    ~A()
    {
        cout << "~A()" << endl;
    }

    void dis()
    {
        cout << "auto_ptr" << endl;
    }
};

class SmartPointer {
public:
    SmartPointer(A* pa):pa_(pa)
    {

    }

    ~SmartPointer()
    {
        delete pa_;
    }

    A* &operator->()
    {
        return pa_;
    }

private:
    A* pa_;
};

void func()
{
    //auto_ptr<A> ap(new A);
    SmartPointer sp(new A);
    sp->dis();
}

int main(int argc, char** argv)
{
    func();


    system("pause");
    return 0;
}

8.3.3 保护代理

在这里插入图片描述

9 装饰模式(Decorator)

9.1 定义

Attach additional responsibilities to an object dynamically keeping the same interface. Decorators provide a flexible alternative to subclassing for extending functionality。
动态地给一个对象添加一些额外的职责。就增加功能来说, 装饰模式相比生成子类更为灵活。

当有太多的类去继承自一个父类时,就会形成类爆炸,如下:
在这里插入图片描述
简而言之,装饰模式,就是用另一种方式来取代继承。

意图动态地给一个对象添加一些额外的职责
问题有时我们希望给某个对象而不是整个类添加一些功能。即动态的为对象添加新的功能。
解决方案采用组合而非单纯继承的方式。扩展一个对象的功能。
实现创建一个原始抽象类和要添加类上的新功能。让实体类和装饰类分别继承自原始抽象类。装饰类中包含原始抽象类的引用。

9.2 类图关系

在这里插入图片描述

9.3 装饰者模式

//装饰模式
class Phone {
public:
    virtual int cost() = 0;
};

class IPhone:public Phone {
public:
    int cost()
    {
        return 7400;
    }
private:

};

class DecoratePhone:public Phone {
public:
    DecoratePhone(Phone* ph) :phone_(ph)
    {

    }
protected:
    Phone* phone_;
};

class ScreenProtector:public DecoratePhone {
public:
    ScreenProtector(Phone* ph):DecoratePhone(ph)
    {

    }

    int cost()
    {
        return 100 + phone_->cost();
    }
};

class HeadSet :public DecoratePhone {
public:
    HeadSet(Phone* ph) :DecoratePhone(ph)
    {

    }

    int cost()
    {
        return 200 + phone_->cost();
    }
};

int main(int argc, char** argv)
{
    //IPhone ip;
    //cout << ip.cost() << endl;

    //ScreenProtector sp(&ip);
    //cout << sp.cost() << endl;

    //HeadSet hs(&sp);
    //cout << hs.cost() << endl;

    Phone* iphone = new HeadSet(new ScreenProtector(new ScreenProtector(new IPhone)));
    cout << iphone->cost() << endl;

    system("pause");
    return 0;
}

10 适配器模式(Adapter)

10.1 定义

Convert the interface of a class into another interface clients expect. Adapter lets classes work together that couldn’t otherwise because of incompatible interfaces.( 将一个类的接口变换成客户端所期待的另一种接口, 从而使原本因接口不匹配而无法在一起工作的两个类能够在一起工作 )。

它包括类适配器和对象适配器,本文针对的是对象适配器。Adapter 模式让我们在设计时不必再关心现存类接口问题。

在这里插入图片描述

10.2 类图关系

在这里插入图片描述
Client为客户端,客户端需要一个Target里的 request() 接口,但是我们所提供的接口是Adaptee里的 speciaRequest() 接口,这时候,我们就可以通过添加一个Adapter类来实现Target里的request接口,然后再在Adaptee里包含一个适配器,从而使得客户可以在Target里调用我们提供的接口(在使用父类的地方,都可以使用子类)。

10.3 实例

10.3.1 引例(披着羊皮的狼)

在这里插入图片描述

10.3.1.2 实现

//披着羊皮的狼
class Goat {
public:
    virtual void miemie() = 0;
};

class NormalGoat:public Goat {
public:
    void miemie()
    {
        cout << "miemiemie羊" << endl;
    }
};

class Wolf {
public:
    void howl()
    {
        cout << "woo狼" << endl;
    }
};

class Adapter :public Goat {
public:
    Adapter(Wolf* wf):wf_(wf)
    {

    }

    ~Adapter()
    {
        cout << "~Adapter" << endl;
        delete wf_;
    }

    void miemie()
    {
        wf_->howl();
    }

protected:
    Wolf* wf_;
};

int main01(int argc, char** argv)
{
    Goat* pw = new Adapter(new Wolf);
    pw->miemie();
 

    system("pause");
    return 0;
}

10.3.2 实战分析

在 STL 中就用到了适配器模式。STL 实现了一种数据结构,称为双端队列(deque),支持前后两段的插入与删除。STL 实现栈和队列时,没有从头开始定义它们,而是直接使用双端队列实现的。这里双端队列就扮演了适配器的角色。队列用到了它的后端插入,前端删除而栈用到了它的后端插入,后端删除。假设栈和队列都是一种顺序容器,有两种操作:压入和弹出。
在这里插入图片描述

10.3.3 实现

//STL适配器容器
class MyDeque {
public:
    void push_back();
    void push_front();
    void pop_back();
    void pop_front();
};

class MyStack {
public:
    void push()
    {
        md->push_back();
    }
    void pop()
    {
        md->pop_back();
    }
protected:
    MyDeque* md;
};

class MyQueue {
public:
    void enQueue()
    {
        md->push_back();
    }

    void deQueue()
    {
        md->pop_front();
    }

protected:
    MyDeque* md;
};

11 桥接模式

11.1 定义

Decouple an abstraction from its implementation so that the two can vary independently. 将抽象部分与它的实现部分分离,使得它们可以独立地变化。

桥梁模式(Bridge Pattern)也叫做桥接模式。桥梁模式的重点是在“解耦”上, 如何让它们两者解耦是我们要了解的重点。

当一个抽象可能有多个实现时,通常用继承来协调它们。抽象类定义对该抽象的接口,而具体的子类则用不同方式加以实现。但是此方法有时不够灵活。继承机制将抽象部分与它实现部分固定在一起,使得难以对抽象部分和实现部分独立地进行修改、扩充和重用。
在这里插入图片描述

11.2 类图关系

在这里插入图片描述

11.3 实例讲解

11.3.1 应用场景分析

11.3.2 实战代码

左手画形,右手画线
在这里插入图片描述

//左手画形,右手画线
class Line {
public:
    virtual void drawLine() = 0;
};

class DotLine :public Line {
public:
    void drawLine()
    {
        cout << "使用点线绘制 ";
    }
};

class SolidLine :public Line {
public:
    void drawLine()
    {
        cout << "使用实线绘制 ";
    }
};

class Shape {
public:
    Shape(int x = 0, int y = 0, Line* pl= nullptr) :x_(x), y_(y),pl_(pl){}
    virtual void drewShape() = 0;

protected:
    int x_, y_;
    Line* pl_;
};

class Circle :public Shape
{
public:
    Circle(int x = 0, int y = 0, int r = 0, Line* pl = 0) :Shape(x, y,pl), r_(r){}

    void drewShape()
    {
        pl_->drawLine();
        cout << "Draw Circle From (" << x_ << ", " << y_ << "), r = " << r_ << endl;

    }

protected:
    int r_;

};

class Rectage :public Shape
{
public:
    Rectage(int x = 0, int y = 0, int w = 0, int l = 0, Line* pl = nullptr) :Shape(x, y, pl), w_(w), l_(l)
    {
    }

    void drewShape()
    {
        pl_->drawLine();
        cout << "Draw Rectage From (" << x_ << ", " << y_ << "), w = " << w_
            << ", l = " << l_ << endl;
    }

protected:
    int w_, l_;

};

int main(int argc, char** argv)
{
    Line* dl = new DotLine;
    Shape* c = new Circle(1,1,5,dl);
    c->drewShape();

    Line* sl = new SolidLine();
    Shape* r = new Rectage(2, 2, 3, 4, sl);
    r->drewShape();

    system("pause");
    return 0;
}

12 工厂模式

12.1 定义

Define an interface for creating an object,but let subclasses decide which class toinstantiate.Factory Method lets a class defer instantiation to subclasses.
定义一个用于创建对象的接口,让子类决定实例化哪一个类。 Factory Method 使一个类的实例化延迟到其子类
在这里插入图片描述

12.2 类图关系

12.2.1 简单工厂

在这里插入图片描述

enum CpuType {
   CoreA, CoreB, CoreC//枚举所有可生产对象
};
class CPU {
public:
    virtual void work() = 0;
};

class SingCoreA: public CPU {
public:
    void work()
    {
        cout << "SingCoreA is working..." << endl;
    }
};

class SingCoreB : public CPU {
public:
    void work()
    {
        cout << "SingCoreB is working..." << endl;
    }
};

//工厂
class Factory {
public:
    CPU* createCpu(enum CpuType type)
    {
        if (type == CoreA)
            return new SingCoreA;

        else if (type == CoreB)
            return new SingCoreB;
    }
};

12.2.2 工厂模式

在这里插入图片描述

//工厂模式
enum CpuType {
    CoreA, CoreB, CoreC//枚举所有可生产对象
};

class CPU {
public:
    virtual void work() = 0;
};

class SingCoreA : public CPU {
public:
    void work()
    {
        cout << "SingCoreA is working..." << endl;
    }
};

class SingCoreB : public CPU {
public:
    void work()
    {
        cout << "SingCoreB is working..." << endl;
    }
};

class Factory {
public:
    virtual CPU* createCpu() = 0;
};

class FactoryA : public Factory {
public:
    CPU* createCpu()
    {
        return new SingCoreA;
    }
};

class FactoryB : public Factory {
public:
    CPU* createCpu()
    {
        return new SingCoreB;
    }
};

13 面向过程/面向对象比较与实践

13.1 面向过程设计TODO

TODO

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值