设计模式概览

来源:互联网 发布:电子科技集团14所 知乎 编辑:程序博客网 时间:2024/06/08 10:31

一、UML基础

UML(United Modeling Language, 统一建模语言): 是一种基于面向对象的可视化建模语言; 
UML 采用一组形象化的图形(如类图)符号作为建模语言, 使用这些符号可以形象地描述系统的各个方面;
UML 通过建立图形之间的各种关系(如类与类之间的关系)来描述模型;
UML 中的关系主要包括 4 种:关联关系(association);依赖关系(dependency);泛化关系(generalization)(继承);实现关系(realization);
      
1)、用例图
用例图(Use Case Diagram): 也称为用户模型图, 是从软件需求分析到最终实现的第一步, 它是从客户的角度来描述系统功能
2)、类图
类图主要是用来显示系统中的类, 接口以及它们之间的关系.
3)、对象图
对象图是类图的一个实例, 用于显示系统执行时的一个可能的快照. 即在某一个时间上系统可能出现的样子. 表现对象的特征.对象图展现了多个对象的特征及对象之间的交互.
4)、时序图
时序图用于描述对象之间的传递消息的时间顺序, 即用例中的行为顺序. 
5)、活动图
活动图本质上就是流程图. 它用于描述系统的活动, 判定点和分支等.
6)、状态图
状态图通过建立对象的生存周期模型来描述对象随时间变化的动态行为
7)、协作图
时序图侧重于对象间消息传递在时间上的先后关系;而协作图表达对象间的的交互过程及对象间的关联关系。

二、设计模式分类及基本原则

设计模式(Design pattern)是一套被反复使用、多数人知晓的、经过分类编目的、代码设计经验的总结。使用设计模式是为了可重用代码、让代码更容易被他人理解、保证代 码可靠性。 毫无疑问,设计模式于己于他人于系统都是多赢的;设计模式使代码编制真正工程化;把简单的问题复杂化(标准化),把环境中的各个部分进行抽象、归纳、解耦合。
设计模式的分类:
    创建型模式 :  通常和对象的创建有关,涉及到对象实例化的方式。(共5种模式)
    结构型模式: 描述的是如何组合类和对象以获得更大的结构。(共7种模式)
    行为型模式: 用来对类或对象怎样交互和怎样分配职责进行描述。(共11种模式)

创建型模式用来处理对象的创建过程,主要包含以下5种设计模式: 
1,工厂方法模式(Factory Method Pattern)的用意是定义一个创建产品对象的工厂接口,将实际创建工作推迟到子类中。
2,抽象工厂模式(Abstract Factory Pattern)的意图是提供一个创建一系列相关或者相互依赖的接口,而无需指定它们具体的类。
3,建造者模式(Builder Pattern)的意图是将一个复杂的构建与其表示相分离,使得同样的构建过程可以创建不同的表示。
4,原型模式(Prototype Pattern)是用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象。
5,单例模式(Singleton Pattern)是保证一个类仅有一个实例,并提供一个访问它的全局访问点。
 
结构型模式用来处理类或者对象的组合,主要包含以下7种设计模式:
6,代理模式(Proxy Pattern)就是为其他对象提供一种代理以控制对这个对象的访问。
7,装饰者模式(Decorator Pattern)动态的给一个对象添加一些额外的职责。就增加功能来说,此模式比生成子类更为灵活。 
8,适配器模式(Adapter Pattern)是将一个类的接口转换成客户希望的另外一个接口。使得原本由于接口不兼容而不能一起工作的那些类可以一起工作。 
9,桥接模式(Bridge Pattern)是将抽象部分与实际部分分离,使它们都可以独立的变化。
10,组合模式(Composite Pattern)是将对象组合成树形结构以表示“部分--整体”的层次结构。使得用户对单个对象和组合对象的使用具有一致性。
11,外观模式(Facade Pattern)是为子系统中的一组接口提供一个一致的界面,此模式定义了一个高层接口,这个接口使得这一子系统更加容易使用。
12,享元模式(Flyweight Pattern)是以共享的方式高效的支持大量的细粒度的对象。
 
行为型模式用来对类或对象怎样交互和怎样分配职责进行描述,主要包含以下11种设计模式:
13,模板方法模式(Template Method Pattern)使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤。 
14,命令模式(Command Pattern)是将一个请求封装为一个对象,从而使你可用不同的请求对客户端进行参数化;对请求排队或记录请求日志,以及支持可撤销的操作。
15,责任链模式(Chain of Responsibility Pattern),在该模式里,很多对象由每一个对象对其下家的引用而连接起来形成一条链。请求在这个链上传递,直到链上的某一个对象决定处理此请求,这使得系统可以在不影响客户端的情况下动态地重新组织链和分配责任。 
16,策略模式(Strategy Pattern)就是准备一组算法,并将每一个算法封装起来,使得它们可以互换。
17,中介者模式(Mediator Pattern)就是定义一个中介对象来封装系列对象之间的交互。终结者使各个对象不需要显示的相互调用 ,从而使其耦合性松散,而且可以独立的改变他们之间的交互。
18,观察者模式(Observer Pattern)定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新。
19,备忘录模式(Memento Pattern)是在不破坏封装的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态。
20,访问者模式(Visitor Pattern)就是表示一个作用于某对象结构中的各元素的操作,它使你可以在不改变各元素的类的前提下定义作用于这些元素的新操作。
21,状态模式(State Pattern)就是对象的行为,依赖于它所处的状态。
22,解释器模式(Interpreter Pattern)就是描述了如何为简单的语言定义一个语法,如何在该语言中表示一个句子,以及如何解释这些句子。 
23,迭代器模式(Iterator Pattern)是提供了一种方法顺序来访问一个聚合对象中的各个元素,而又不需要暴露该对象的内部表示。

设计模式基本原则:最终目的:高内聚,低耦合
1)  开放封闭原则  (OCP,Open For Extension, Closed For Modification Principle)
            类的改动是通过增加代码进行的,而不是修改源代码。
2)  单一职责原则  (SRP,Single Responsibility Principle)
            类的职责要单一,对外只提供一种功能,而引起类变化的原因都应该只有一个。
3)   依赖倒置原则 (DIP,Dependence Inversion Principle)
            依赖于抽象(接口),不要依赖具体的实现(类),也就是针对接口编程。
4)   接口隔离原则 (ISP,Interface Segegation Principle)
            不应该强迫客户的程序依赖他们不需要的接口方法。一个接口应该只提供一种对外功能,不应该把所有操作都封装到一个接口中去。
5)   里氏替换原则 (LSP, Liskov Substitution Principle)
       任何抽象类出现的地方都可以用他的实现类进行替换。实际就是虚拟机制,语言级别实现面向对象功能。
6)   优先使用组合而不是继承原则(CARP,Composite/Aggregate Reuse Principle)
             如果使用继承,会导致父类的任何变换都可能影响到子类的行为。
             如果使用对象组合,就降低了这种依赖关系。
7)  迪米特法则(LOD,Law of Demeter)
             一个对象应当对其他对象尽可能少的了解,从而降低各个对象之间的耦合,提高系统的可维护性。例如在一个程序中,各个模块之间相互调用时,通常会提供一个统一的接口来实现。这样其他模块不需要了解另外一个模块的内部实现细节,这样当一个模块内部的实现发生改变时,不会影响其他模块的使用。(黑盒原理)

三、设计模式详解之——创建型模式

1、单例模式

单例模式的定义是:保证一个类、只有一个实例存在,同时提供能对该实例加以访问的全局访问方法。在整个程序空间中,该类只存在一个实例对象。从下图可以看出Singleton()构造函数是一个私有的。
    
单例模式应用场景:
在应用系统开发中,我们常常有以下需求:
- 在多个线程之间,比如初始化一次socket资源;比如servlet环境,共享同一个资源或者操作同一个对象
- 在整个程序空间使用全局变量,共享资源
- 大规模系统中,为了性能的考虑,需要节省对象的创建时间等等。
因为Singleton模式可以保证为一个类只生成唯一的实例对象,所以这些情况,Singleton模式就派上用场了。
实现单例步骤常用步骤:   
a)构造函数私有化
b)提供一个全局的静态方法(全局访问点)
c)在类中定义一个静态指针,指向本类的变量的静态变量指针
(1)懒汉模式单例——只有在获取单例时,才把对象new出来。
#include<iostream>using namespace std;class Singleton{private:Singleton(){cout << "Singleton 构造函数执行!" << endl;}public:static Singleton *getInstance(){if (m_pSingleton == NULL)  //懒汉式单例:1、每次获取实例都要判断;2、多线程会有问题{m_pSingleton = new Singleton;}return m_pSingleton;}static void freeInstance(){if (m_pSingleton != NULL){delete m_pSingleton;m_pSingleton = NULL;}}private:static Singleton *m_pSingleton;};Singleton* Singleton::m_pSingleton = NULL;void main(){Singleton *p1 = Singleton::getInstance();//懒汉式——只有在获取单例时,才把对象new出来Singleton *p2 = Singleton::getInstance();if (p1 == p2){cout << "p1和p2是同一个对象!" << endl;}else{cout << "p1和p2不是同一个对象!" << endl;}Singleton::freeInstance();}//Singleton 构造函数执行一次!打印p1和p2是同一个对象!
为什么说懒汉式遇上多线程会出现问题?详细内容见:懒汉式单例的多线程问题——
比如我们在Singleton的构造函数中加上sleep(1000),当第一个线程到来时判断为NULL,去创建,并中间挂起;当第二个线程到来时,仍旧判断为NULL,依次类推,这就不是单个实例了。
(2)饿汉模式单例
#include<iostream>using namespace std;class Singleton{private:Singleton(){cout << "Singleton 构造函数执行!" << endl;}public:static Singleton *getInstance(){//if (m_pSingleton == NULL)  //懒汉式单例:1、每次获取实例都要判断——降低了效率;2、多线程会有问题//{//m_pSingleton = new Singleton;//}return m_pSingleton;}static void freeInstance(){if (m_pSingleton != NULL){delete m_pSingleton;m_pSingleton = NULL;}}private:static Singleton *m_pSingleton;};//Singleton* Singleton::m_pSingleton = NULL;         //懒汉式——懒汉式 并没有创建单例对象Singleton* Singleton::m_pSingleton = new Singleton;  //饿汉式——不管你创建不创建实例,均把实例new出来,浪费了内存空间void main(){Singleton *p1 = Singleton::getInstance();    //懒汉式——只有在获取单例时,才把对象new出来Singleton *p2 = Singleton::getInstance();if (p1 == p2){cout << "p1和p2是同一个对象!" << endl;}else{cout << "p1和p2不是同一个对象!" << endl;}Singleton::freeInstance();}//Singleton 构造函数执行一次!打印p1和p2是同一个对象!

2、简单工厂模式

 又叫做静态工厂方法模式。通过专门定义一个类来负责创建其他类的实例,被创建的实例通常都具有共同的父类。
class Fruit {public:virtual void getFruit() = 0;};class Banana : public Fruit{public:virtual void getFruit(){cout << "我是香蕉...." << endl;}};class Apple : public Fruit{public:virtual void getFruit(){cout << "我是苹果...." << endl;}};class Factory{public:Fruit *create(char *p){if (strcmp(p, "banana") == 0){return new Banana; }else if (strcmp(p, "apple") == 0){return new Apple;}else{printf("不支持\n" ) ;return NULL;}}};void main(){Factory *f = new Factory;Fruit *fruit = NULL;//工厂生产 香蕉fruit = f->create("banana");fruit->getFruit();delete fruit;        //工厂生产苹果fruit = f->create("apple");fruit->getFruit();delete fruit;delete f;}
       在这个模式中,工厂类是整个模式的关键所在,它包含必要的判断逻辑,能够根据外界给定的信息,决定究竟应该创建哪个具体类的对象。用户在使用时可以直接根据工厂类去创建所需的实例,而无需了解这些对象是如何创建以及如何组织的。有利于整个软件体系结构的优化。简单工厂模式的缺点也正体现在其工厂类上,由于工厂类集中了所有实例的创建逻辑,所以“高内聚”方面做的并不好。另外,当系统中的具体产品类不断增多时,可能会出现要求工厂类也要做相应的修改,扩展性并不很好。核心思想是用一个工厂来根据输入的条件产生不同的类,然后根据不同类的virtual函数得到不同的结果。
  GOOD:适用于不同情况创建不同的类时;BUG:客户端必须要知道基类和工厂类,耦合性差

3、(多态)工厂模式

又被称为多态工厂模式 。工厂方法模式的意义是定义一个创建产品对象的工厂接口,将实际创建工作推迟到子类当中。核心工厂类不再负责产品的创建,这样核心类成为一个抽象工厂角色,仅负责具体工厂子类必须实现的接口,这样进一步抽象化的好处是使得工厂方法模式可以使系统在不修改具体工厂角色的情况下引进新的产品。

class Fruit{public:virtual void  sayname()  = 0;};class  Banana : public Fruit{public:void  sayname(){cout << "我是香蕉" << endl;}};class  Apple : public Fruit{public:void  sayname(){cout << "我是 Apple" << endl;} };class  AbFactory     //抽象工厂{public:virtual Fruit *CreateProduct() = 0;};class BananaFactory :public AbFactory   //具体工厂{public:virtual Fruit *CreateProduct(){return new Banana;}};class AppleFactory :public AbFactory    //具体工厂{public:virtual Fruit *CreateProduct(){return new Apple;}};///////////////////////////////////////////////////////////////////////////////////添加新的产品——添加新功能,增加代码,而不是去修改原来的代码(比较简单工厂模式)class Pear : public Fruit{public:virtual void sayname(){cout << "我是 pear" << endl;}protected:private:};class PearFactory : public AbFactory{public:virtual Fruit *CreateProduct(){return new Pear;}};void main(){AbFactory*factory = NULL;Fruit*fruit = NULL;//吃 香蕉factory = new BananaFactory;fruit = factory->CreateProduct();fruit->sayname();delete fruit;delete factory;//Pear factory = new PearFactory;fruit = factory->CreateProduct();fruit->sayname();delete fruit;delete factory;}
       具体工厂类都有共同的接口,或者有共同的抽象父类。当系统扩展需要添加新的产品对象时,仅仅需要添加一个具体对象以及一个具体工厂对象,原有工厂对象不需要进行任何修改,也不需要修改客户端,很好的符合了“开放-封闭”原则。

4、抽象工厂模式

抽象工厂模式可以向客户端提供一个接口,使得客户端在不必指定产品的具体类型的情况下,能够创建多个产品族的产品对象。
工厂模式只能生产一个产品。(要么香蕉、要么苹果)
抽象工厂可以一下生产一个产品族(里面有很多产品组成)

class Fruit{public:virtual void SayName() = 0;};class AbstractFactory{//产品族public:virtual Fruit* CreateBanana() = 0;virtual Fruit* CreateApple() = 0;};class NorthBanana : public Fruit{public:virtual void SayName(){cout << "我是北方香蕉" << endl;}};class NorthApple : public Fruit{public:virtual void SayName(){cout << "我是北方苹果" << endl;}};class SourthBanana : public Fruit{public:virtual void SayName(){cout << "我是南方香蕉" << endl;}};class SourthApple : public Fruit{public:virtual void SayName(){cout << "我是南方苹果" << endl;}};class NorthFacorty : public AbstractFactory      //北方工厂{//产品族virtual Fruit * CreateBanana(){return new NorthBanana;}virtual Fruit * CreateApple(){return new NorthApple;}};class SourthFacorty : public AbstractFactory    //南方工厂{//产品族virtual Fruit * CreateBanana(){return new SourthBanana;}virtual Fruit * CreateApple(){return new SourthApple;}};void main(){//客户端面向抽象类编程Fruit*fruit = NULL;AbstractFactory *af = NULL;//------af = new SourthFacorty;  //南方工厂fruit = af->CreateApple();fruit->SayName();delete fruit;fruit = af->CreateBanana();fruit->SayName();delete fruit;//------af = new NorthFacorty;  //北方工厂fruit = af->CreateApple();fruit->SayName();delete fruit;fruit = af->CreateBanana();fruit->SayName();delete fruit;delete af;}

5、建造者模式(builder)

Builder模式是一种对象创建型模式之一,用来隐藏复合对象的创建过程,它把复合对象的创建过程加以抽象,通过子类继承和重载的方式,动态地创建具有复合属性的对象。适用情况:一个对象的构建比较复杂,将一个对象的构建(**)和对象的表示(**)进行分离。
class House{public:void setDoor(string door){this->m_door = door;}void setWall(string wall){this->m_wall = wall;}void setWindow(string window){this->m_window = window;}//--string getDoor(){cout << m_door << endl;return this->m_door;}string getWall(){cout << m_wall << endl;return this->m_wall;}string getWindow(){cout << m_window << endl;return m_window;}private:stringm_door;stringm_wall;stringm_window;};class  Builder  //把工程队抽象出来——实现多个、多种工程队{public:virtual void buildWall() = 0;virtual void buildDoor() = 0;virtual void buildWindow() = 0;virtual House* getHouse() = 0;    //获取结果};//公寓 flat 工程队class  FlatBuilder : public Builder{public:FlatBuilder(){m_house = new House;}virtual void buildWall(){m_house->setWall("flat wall");}virtual void buildDoor(){m_house->setDoor("flat door");}virtual void buildWindow(){m_house->setWindow("flat window");}virtual House* getHouse(){return m_house;}private:House *m_house;};//别墅 villa 工程队class  VillaBuilder : public Builder{public:VillaBuilder(){m_house = new House;}virtual void buildWall(){m_house->setWall("villa wall");}virtual void buildDoor(){m_house->setDoor("villa door");}virtual void buildWindow(){m_house->setWindow("villa window");}virtual House* getHouse(){return m_house;}private:House *m_house;};//设计师(指挥者):负责建造业务逻辑,修改该类可以随时改变业务逻辑  //建筑队:干具体的活//这就是 对象的构建 和 对象的表示 进行分离,把 建造具体事务过程 和 建造业务逻辑 进行分离class Director{public:Director(Builder * build){m_build = build;}void Construct(){m_build->buildWall();m_build->buildWindow();m_build->buildDoor();}private:Builder * m_build;};void main(){/*客户直接造房子House *house = new House;house->setDoor("门");house->setWall("墙面");//一方面,该建造过程较为复杂,所以应该单独地封装为一个类house->setWindow("窗口");//另一方面,如果在客户端需要增加建造过程中的步骤,还需要去修改“该类”的源代码delete house;*/House*house = NULL;Director*director = NULL;Builder*builder = NULL;cout <<  "Villa:" << endl;// 请一个建造别墅 Villa 的工程队builder = new VillaBuilder;//设计师 指挥 工程队 干活director = new Director(builder);director->Construct();house = builder->getHouse();house->getWall();house->getWindow();house->getDoor();delete house;delete builder;cout << endl << "Flat:" << endl;//请 FlatBuilder 公寓 工程队builder = new FlatBuilder;director = new Director(builder);director->Construct();house = builder->getHouse();house->getWall();house->getWindow();house->getDoor();delete house;delete builder;delete director;}
Factory模式:
1、有一个抽象的工厂。
2、实现一个具体的工厂---汽车工厂。
3、工厂生产汽车A,得到汽车产品A。
4、工厂生产汽车B,得到汽车产品B。  
这样做,实现了购买者和生产线的隔离。强调的是结果。     
Builder模式:
1、引擎工厂生产引擎产品,得到汽车部件A。
2、轮胎工厂生产轮子产品,得到汽车部件B。
3、底盘工厂生产车身产品,得到汽车部件C。
4、将这些部件放到一起,形成刚好能够组装成一辆汽车的整体。
5、将这个整体送到汽车组装工厂,得到一个汽车产品。
这样做,目的是为了实现复杂对象生产线和其部件的解耦。强调的是过程

两者的区别在于:
Factory模式不考虑对象的组装过程,而直接生成一个我想要的对象。
Builder模式先一个个的创建对象的每一个部件,再统一组装成一个对象。
Factory模式所解决的问题是,工厂生产产品。
而Builder模式所解决的问题是工厂控制产品生成器组装各个部件的过程,然后从产品生成器中得到产品。
Builder模式不是很常用。

6、原型模式(prototype)

Prototype模式是一种对象创建型模式,它采取 复制原型对象的方法 来创建对象的实例。使用Prototype模式创建的实例,具有与原型一样的数据。适用情况:让一个复杂对象,具有自我复制功能,统一一套接口。1)由原型对象自身创建目标对象。也就是说,对象创建这一动作发自原型对象本身。2)目标对象是原型对象的一个克隆。也就是说,通过Prototype模式创建的对象,不仅仅与原型对象具有相同的结构,还与原型对象具有相同的值。3)根据对象克隆深度层次的不同,有浅度克隆与深度克隆。
class Person{public:virtual Person* clone() = 0;  //让该类具有自我复制功能(当该对象的复制较为复杂时)virtual void printT() = 0;};class  CPlusPlusProgrammer : public Person{public:CPlusPlusProgrammer(){m_name = "";m_age = 0;m_resume = NULL;setResume("英语六级、GRE");}CPlusPlusProgrammer(string name, int age){m_name = name;m_age = age;m_resume = NULL;setResume("英语六级、GRE");}void setResume(char *p){if (m_resume != NULL){delete m_resume;}m_resume = new char[strlen(p) + 1];//下图扭转指针,防止浅拷贝strcpy(m_resume, p);}virtual void printT(){cout << "m_name:" << m_name << "  m_age:" << m_age << "  m_resume:" << m_resume << endl;}virtual Person* clone()   //克隆接口的实现{CPlusPlusProgrammer *tmp = new CPlusPlusProgrammer;*tmp = *this;   // =操作 浅拷贝return tmp;}private:stringm_name;intm_age;char*m_resume;  //类中有指针,涉及到浅拷贝、深拷贝的问题};void main(){Person *c1 = new CPlusPlusProgrammer("张三", 32);c1->printT();Person *c2 = c1->clone(); //复制,尤其注意m_resume虽然最后打印结果一样,但是指向的是两块不同的内存空间c2->printT();}
       


       上述介绍了几种创建型模式——单例模式、简单工厂模式,多态工厂模式、抽象工厂模式、建造者模式、原型模式(prototype),接下来介绍结构型模式http://blog.csdn.net/songshimvp1/article/details/48970017——代理模式、装饰模式、适配器模式(adapter)、组合模式、桥接模式(bridge)、外观模式(facade)、享元模式(flyweight)。

0 0
原创粉丝点击