第二周(Geek Band)

---------------------对象创建--------------------

通过【对象创建模式】绕开new,来避免对象创建(new)过程中所导致的紧耦合(依赖具体类),从而支持对象创建的稳定。它是接口抽象之后的第一步工作。

工厂:Factory Method
抽象工厂:Abstract Factory
原型:Prototype
建造者:Builder


工厂:Factory Method

动机:

在软件系统中,经常面临着创建对象的工作;由于需求的变化,需要创建的对象的具体类型经常变化。

如何应对这种变化?如何绕过常规的对象创建方法(new),提供一种“封装机制”来避免客户程序和这种“具体对象创建工作”的紧耦合?

定义:

定义一个用于创建对象的接口,让子类决定实例化哪一个类
Factory Method使得一个类的实例化延迟(目的:解耦--------------手段:虚函数)到子类

结构:
结构
要点总结:

Factory Method模式用于隔离类对象的使用者与具体类型之间的耦合关系。面对一个经常变化的具体类型,紧耦合关系(new)会导致软件的脆弱。

Factory Method模式通过面向对象的手法,将所有创建的具体对象延迟到子类,从而实现一种扩展(而非更改)的策略,较好地解决了这种紧耦合关系。

Factory Method模式解决“单个对象”的需求变化。缺点在于要求创建方法/参数相同。

代码举例:

仍然考虑文件分割器案例,不考虑与创建对象无关的代码部分,暂时忽略内存管理,专注于工厂方法模式的应用。

方法1

在实现代码1中,不同类型的文件分割器类(File,Pic,Video等)继承文件分割器抽象基类。

在MainForm中,MainForm类依赖(编译时依赖)了具体的类BinarySpitter,违背了依赖倒置原则。此时即出现了动机中说明的创建对象过程中导致的紧耦合。

//MainForm1
class MainForm : public Form
{
    TextBox* txtFilePath;
    TextBox* txtFileNumber;
    ProgressBar* progressBar;

public:
    void Button1_Click(){
        
        ISplitter * splitter=
            new BinarySplitter();//依赖具体类 ,违背了依赖倒置原则。细节依赖    
        splitter->split();

    }
};


//FileSplitter1
class ISplitter{
public:
    virtual void split()=0;
    virtual ~ISplitter(){}
};
class BinarySplitter : public ISplitter{    
};

class TxtSplitter: public ISplitter{    
};

class PictureSplitter: public ISplitter{    
};

class VideoSplitter: public ISplitter{    
};

方法2

1.绕开new,依赖抽象;所以考虑创建一个类,利用其中方法的返回值作为创建对象的结果;

2.然而单纯的返回一个具体类的对象仍然没有解决依赖倒置的问题,所以考虑将该类设计为一个抽象类,具体的返回由其子类来确定。

3.依照上述思想创建工厂基类SplitterFactory(抽象类),具体工厂(BinarySplitterFactory等)返回具体的对象。

4.MainForm使用过程中,声明一个工厂字段,在具体创建对象过程中采用统一的依赖于抽象的创建方法,即

ISplitter * splitter= factory->CreateSplitter(); //相当于多态new

而factory具体指向的对象类型由MainForm构造函数通过外界传入。

//ISpiltterFactory.cpp

//抽象类
class ISplitter{
public:
    virtual void split()=0;
    virtual ~ISplitter(){}
};


//工厂基类
class SplitterFactory{
public:
    virtual ISplitter* CreateSplitter()=0;
    virtual ~SplitterFactory(){}
};

//FileSpiltter2.cpp

//具体类
class BinarySplitter : public ISplitter{
    
};

class TxtSplitter: public ISplitter{
    
};

class PictureSplitter: public ISplitter{
    
};

class VideoSplitter: public ISplitter{
    
};

//具体工厂
class BinarySplitterFactory: public SplitterFactory{
public:
    virtual ISplitter* CreateSplitter(){
        return new BinarySplitter();
    }
};

class TxtSplitterFactory: public SplitterFactory{
public:
    virtual ISplitter* CreateSplitter(){
        return new TxtSplitter();
    }
};

class PictureSplitterFactory: public SplitterFactory{
public:
    virtual ISplitter* CreateSplitter(){
        return new PictureSplitter();
    }
};

class VideoSplitterFactory: public SplitterFactory{
public:
    virtual ISplitter* CreateSplitter(){
        return new VideoSplitter();
    }
};

//MainForm2.cpp
class MainForm : public Form
{
    SplitterFactory*  factory;//工厂

public:
    
    MainForm(SplitterFactory*  factory){
        this->factory=factory;
    }
    
    void Button1_Click(){

        
        ISplitter * splitter=
            factory->CreateSplitter(); //多态new
        
        splitter->split();

    }
};
结论:可以从上述分析和代码中看出,工厂方法模式的使用,并不是为了消除变化(事实上变化不可能消除),而是将变化排除在MainForm之外(类比将变化赶到一个小范围),使其更加可控,从而使文件分割器的设计和使用满足面向对象设计原则,在应对变化时表现出优势。

抽象工厂:Abstract Factory

动机:

在软件系统中,经常面临着“一系列相互依赖的对象”的创建工作;同时,由于需求的变化,往往存在更多系列对象的创建工作。

定义:

提供一个接口,让该接口复杂创建一系列”相关或者相互依赖的对象“,无需指定它们具体的类。

结构:
结构
要点总结:

如果没有应对”多系列对象构建“的需求变化,则没有必要使用Abstract Factory模式,这时使用工厂方法即可。

”系列对象“指的是某一特定系列下的对象之间有相互依赖或作用的关系。不同系列的对象之间不能相互依赖。

Abstract Factory模式主要在于应对”新系列“的需求变动。其缺点在于难以应对”新对象“的需求变动。

代码示例:

实现利用数据库的业务逻辑,支持多数据库(Sql,Oracle等),有连接、命令、读取等功能。

其中命令,连接功能之间有相互联系。

方法一(使用工厂方法):

每个功能类有一个创建的工厂,如IDBConnection与IDBConnectionFactory


//数据库访问有关的基类
class IDBConnection{
    
};
class IDBConnectionFactory{
public:
    virtual IDBConnection* CreateDBConnection()=0;
};


class IDBCommand{
    
};
class IDBCommandFactory{
public:
    virtual IDBCommand* CreateDBCommand()=0;
};


class IDataReader{
    
};
class IDataReaderFactory{
public:
    virtual IDataReader* CreateDataReader()=0;
};


//支持SQL Server
class SqlConnection: public IDBConnection{
    
};
class SqlConnectionFactory:public IDBConnectionFactory{
    
};


class SqlCommand: public IDBCommand{
    
};
class SqlCommandFactory:public IDBCommandFactory{
    
};


class SqlDataReader: public IDataReader{
    
};
class SqlDataReaderFactory:public IDataReaderFactory{
    
};

//支持Oracle
class OracleConnection: public IDBConnection{
    
};

class OracleCommand: public IDBCommand{
    
};

class OracleDataReader: public IDataReader{
    
};



class EmployeeDAO{
    IDBConnectionFactory* dbConnectionFactory;
    IDBCommandFactory* dbCommandFactory;
    IDataReaderFactory* dataReaderFactory;
    
    
public:
    vector<EmployeeDO> GetEmployees(){
        IDBConnection* connection =
            dbConnectionFactory->CreateDBConnection();
        connection->ConnectionString("...");

        IDBCommand* command =
            dbCommandFactory->CreateDBCommand();
        command->CommandText("...");
        command->SetConnection(connection); //关联性

        IDBDataReader* reader = command->ExecuteReader(); //关联性
        while (reader->Read()){

        }

    }
};

分析上述代码:分析上述代码,虽然解决了组件创建的问题。但是仔细考虑,由于功能之间具有关联性,不同类型数据库的对象并不能同时创建搭配(如sql的command和oracle的connection搭配,显然不合理)。所以考虑抽象工厂模式。

方法2:

使用一个工厂,将一系列相互依赖的的对象创建在一个工厂中实现。


//数据库访问有关的基类
class IDBConnection{
    
};

class IDBCommand{
    
};

class IDataReader{
    
};


class IDBFactory{
public:
    virtual IDBConnection* CreateDBConnection()=0;
    virtual IDBCommand* CreateDBCommand()=0;
    virtual IDataReader* CreateDataReader()=0;
    
};


//支持SQL Server
class SqlConnection: public IDBConnection{
    
};
class SqlCommand: public IDBCommand{
    
};
class SqlDataReader: public IDataReader{
    
};


class SqlDBFactory:public IDBFactory{
public:
    virtual IDBConnection* CreateDBConnection()=0;
    virtual IDBCommand* CreateDBCommand()=0;
    virtual IDataReader* CreateDataReader()=0;
 
};

//支持Oracle
class OracleConnection: public IDBConnection{
    
};

class OracleCommand: public IDBCommand{
    
};

class OracleDataReader: public IDataReader{
    
};



class EmployeeDAO{
    IDBFactory* dbFactory;
    
public:
    vector<EmployeeDO> GetEmployees(){
        IDBConnection* connection =
            dbFactory->CreateDBConnection();
        connection->ConnectionString("...");

        IDBCommand* command =
            dbFactory->CreateDBCommand();
        command->CommandText("...");
        command->SetConnection(connection); //关联性

        IDBDataReader* reader = command->ExecuteReader(); //关联性
        while (reader->Read()){

        }

    }
};

原型:Prototype

动机:
  • 在软件系统中,经常面临"某些结构复杂的对象"的创建工作;由于需求的变化,这些对象经常面临着剧烈的变化,但是他们却拥有比较稳定一致的接口。

  • 如何应对这种变化?如何向“客户程序”隔离出“这些易变对象”从而使得依赖这些易变对象的客户程序,不随着需求改变而改变?

定义:

用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象。clone()方法来实现对象的克隆

结构:
结构
要点总结:
  • Prototype模式同样用于隔离类对象的使用者和具体类型(易变)之间的耦合关系,他同样要求这些易变类,拥有稳定的接口

  • Prototype模式采用原型克隆的方法(clone()),来创建易变类的实体对象,可以灵活的动态创建“拥有某些稳定接口”的新对象——所需工作仅仅是注册一个新类的对象(即 原型),然后在任何需要的地方克隆。

  • Prototype模式中,clone的方法【可以利用某些框架中的序列化——针对java】来实现深拷贝(深拷贝即 拷贝构造函数,BIG THREE。)

代码演示:

原型模式 与 抽象工厂的最大区别,对象结构很复杂,使用原型。(是否考虑对象的复杂中间状态?如果中间状态需要保留,用原型模式。)——实际应用过程中比较少。

//Prototype.cpp
//抽象类
class ISplitter{
public:
    virtual void split()=0;
    virtual ISplitter* clone()=0; //通过克隆自己来创建对象
    
    virtual ~ISplitter(){}

};
//ConretePrototype.cpp
//具体类
class BinarySplitter : public ISplitter{
public:
    virtual ISplitter* clone(){
        return new BinarySplitter(*this);
    }
};

class TxtSplitter: public ISplitter{
public:
    virtual ISplitter* clone(){
        return new TxtSplitter(*this);
    }
};

class PictureSplitter: public ISplitter{
public:
    virtual ISplitter* clone(){
        return new PictureSplitter(*this);
    }
};

class VideoSplitter: public ISplitter{
public:
    virtual ISplitter* clone(){
        return new VideoSplitter(*this);
    }
};
//Client.cpp
class MainForm : public Form
{
    ISplitter*  prototype;//原型对象

public:
    
    MainForm(ISplitter*  prototype){
        this->prototype=prototype;
    }
    
    void Button1_Click(){

        ISplitter * splitter=
            prototype->clone(); //克隆原型
        
        splitter->split();
        
        

    }
};

建造者:Builder

动机:
  1. 情形:创建一个复杂对象,由于需求变化,复杂对象的各个部分(子对象)经常面临着剧烈变化,但将它们组合在一起的算法却相对稳定。(模板方法模式 做对比)

  2. 应对方式:提供一种封装机制,来隔离出【复杂对象】的各个部分的变化,从而保持系统中【稳定构建算法】不随需求的改变而发生变化。

定义:

将一个复杂对象的构造与它的表示分离,使同样的构建过程(稳定)可以创建不同的表示(变化)。

结构:
结构
要点总结:
  1. Bulder模式主要用于分步构建一个【复杂的对象】,在这个过程中【分步骤】是一个稳定的算法,各部分【子对象】经常发生变化。

  2. 变化点在哪里,封装在哪里。缺点:难以应对【步骤】算法的变化。

  3. 注意不同语言中,构造器内调用虚函数的差别(如C++、C#等)

  4. 实际代码中,使用较少。

代码演示:

游戏中建房子。

避免类臃肿,将基类house拆分成,建造类专门管构建(HouseBuilder)和基本属性如门、窗等(house )类。同样,子类也做拆分。class StoneHouse: public House{ };class StoneHouseBuilder: public HouseBuilder{}

//builder.CPP
class House{
    //....
};

class HouseBuilder {
public:
    House* GetResult(){
        return pHouse;
    }
    virtual ~HouseBuilder(){}
protected:
    
    House* pHouse;
    virtual void BuildPart1()=0;
    virtual void BuildPart2()=0;
    virtual void BuildPart3()=0;
    virtual void BuildPart4()=0;
    virtual void BuildPart5()=0;
    
};

class StoneHouse: public House{
    
};

class StoneHouseBuilder: public HouseBuilder{
protected:
    
    virtual void BuildPart1(){
        //pHouse->Part1 = ...;
    }
    virtual void BuildPart2(){
        
    }
    virtual void BuildPart3(){
        
    }
    virtual void BuildPart4(){
        
    }
    virtual void BuildPart5(){
        
    }
    
};


class HouseDirector{
    
public:
    HouseBuilder* pHouseBuilder;
    
    HouseDirector(HouseBuilder* pHouseBuilder){
        this->pHouseBuilder=pHouseBuilder;
    }
    
    House* Construct(){
        
        pHouseBuilder->BuildPart1();
        
        for (int i = 0; i < 4; i++){
            pHouseBuilder->BuildPart2();
        }
        
        bool flag=pHouseBuilder->BuildPart3();
        
        if(flag){
            pHouseBuilder->BuildPart4();
        }
        
        pHouseBuilder->BuildPart5();
        
        return pHouseBuilder->GetResult();
    }
};

---------------------接口隔离--------------------

在组件构建过程中,某些接口之间直接的依赖常常会带来很多问题,甚至无法实现,采用添加一层间接(稳定)接口,来隔离本来本来相互关联的接口。从而实现松耦合

门面:Facade(解决系统内与系统外的依赖关系,通过facade实现内外隔离【单向】)
代理:Proxy(两个对象,直接依赖转间接依赖)
中介者:Mediator(多个对象间的相互依赖,转依赖中介)
适配器:Adapter(新老接口不适配,继承新街口,组合老接口)


门面\外观模式:Facade

动机:
系统间耦合的复杂度
A方案——B方案
  1. A方案的问题在于,组件的客户和组件中各种复杂的子系统有了过多的耦合,随着外部客户程序和子系统的演化,这种过多的耦合面临很多复杂变化的挑战(系统不稳定,调整工作量大)

  2. 如何演化客户程序和系统间的交互接口?如何将外部客户程序的演化和内部子系统的变化之间的依赖关系相互解耦?

定义:

为子系统中的一组接口提供一个一致的(稳定)界面,定义一个高层接口,这个接口使得这一子系统更加容易使用(复用)。

结构:
结构
蓝色接口稳定,内部变化不影响接口。内部与外部分离
要点总结:
  1. 从客户程序的角度来看,Facade模式简化了整个组件系统的接口,对于组件内部与外部客户程序来说,达到了一种解耦合的效果——内部子系统的任何变化,不会影响接口的变化;

  2. Facade模式更注重从架构的角度看整个系统,而不是单个类的层次。Facade模式更多时候是一种架构设计模式。【设计素养】

  3. Facade模式并非是一个集装箱,不能放进任意多个对象。【eg:界定为数据访问层,就不应该放界面组件的东西放入】高内聚,松耦合。

  4. Facade模式中组件的内部应该是“相互耦合关系比较大的一系列组件”,而不是一个简单的功能集合。

代码演示:(来自网络)

1.subsystemClasses

/*----------------------------------------------------------------*/
/* class Base                                                     */
/*----------------------------------------------------------------*/
class Base
{
public:
    Base(){};
};

2.以三种信息:SMS,MMS,PUSH为例:checkReady,getContent

/*----------------------------------------------------------------*/
/* class SmsUtil                                                  */
/*----------------------------------------------------------------*/
class SmsUtil: public Base
{
#define SMS_CONTENT "I am sms content"
public:
    SmsUtil(){}
    bool checkReady()
    {
        cout<<"SmsUtil checkReady"<<endl;
        return true;
    }
    bool getSmsContent(int msg_id,char* pContent)
    {
        cout<<"SmsUtil getSmsContent"<<endl;
        strcpy(pContent,SMS_CONTENT);
        return true;
    }
};

/*----------------------------------------------------------------*/
/* class MmsUtil                                                  */
/*----------------------------------------------------------------*/
class MmsUtil: public Base
{
#define MMS_CONTENT "I am mms content"
public:
    MmsUtil(){}
    bool checkReady()
    {
        cout<<"MmsUtil checkReady"<<endl;
        return true;
    }
    bool getMmsContent(int msg_id,char* pContent)
    {
        cout<<"MmsUtil getMmsContent"<<endl;
        strcpy(pContent,MMS_CONTENT);
        return true;
    }
};

/*----------------------------------------------------------------*/
/* class PushUtil                                                 */
/*----------------------------------------------------------------*/
class PushUtil: public Base
{
#define PUSH_CONTENT "I am push content"
public:
    PushUtil(){}
    bool checkReady()
    {
        cout<<"PushUtil checkReady"<<endl;
        return true;
    }
    bool getPushContent(int msg_id,char* pContent)
    {
        cout<<"PushUtil getPushContent"<<endl;
        strcpy(pContent,PUSH_CONTENT);
        return true;
    }
};

3.Facade ——单例类

/*----------------------------------------------------------------*/
/* class MsgFacade                                                */
/*----------------------------------------------------------------*/
enum MsgType
{
    SMS,
    MMS,
    PUSH,
    MSG_ALL
};

class MsgFacade: public Base
{
protected:
    MsgFacade()
    {
        m_sms = new SmsUtil();
        m_mms = new MmsUtil();
        m_push = new PushUtil();
    }
public:
    static MsgFacade* getInstance()
    {
        if (s_instance == NULL)
        {
            s_instance = new MsgFacade();
        }

        return s_instance;
    }
    static void closeInstance()
    {
        delete s_instance;
    }
public:
    bool checkReady(int type)
    {
        bool resutl = false;

        resutl = m_sms->checkReady();
        resutl &= m_mms->checkReady();
        resutl &= m_push->checkReady();

        return resutl;
    }
    bool getMsgContent(int type,int msg_id,char* pContent)
    {
        switch(type)
        {
            case SMS:
            {
                m_sms->getSmsContent(msg_id,pContent);
                break;
            }
            case MMS:
            {
                m_mms->getMmsContent(msg_id,pContent);
                break;
            }
            case PUSH:
            {
                m_push->getPushContent(msg_id,pContent);
                break;
            }
            default:
                break;
        }

        return true;
    }
private:
    SmsUtil* m_sms;
    MmsUtil* m_mms;
    PushUtil* m_push;

    static MsgFacade* s_instance;
};
MsgFacade* MsgFacade::s_instance = NULL;

4.Test

#include "facade.h"

int main()
{
    MsgFacade* msg = MsgFacade::getInstance();
    msg->checkReady(MSG_ALL);
    
    cout<<endl;
    char content[100] = {0};

    msg->getMsgContent(SMS,0,content);
    cout<<content<<endl;
    
    msg->getMsgContent(MMS,0,content);
    cout<<content<<endl;

    msg->getMsgContent(PUSH,0,content);
    cout<<content<<endl;

    return 0;
}

5.Result

SmsUtil checkReady
MmsUtil checkReady
PushUtil checkReady

SmsUtil getSmsContent
I am sms content
MmsUtil getMmsContent
I am mms content
PushUtil getPushContent
I am push content

仅需要一个Facade对象,因此Facade对象通常属于Singleton 模式


代理模式:Proxy

动机:

在面向对象系统中,有些对象由于某种原因(比如对象创建的开销很大,或者某些操作需要安全控制,或者需要进程外的访问等)直接访问会给使用者或者系统结构,带来很大麻烦

如何在【不失去透明操作对象的同时】来管理、控制这些对象特有的复杂性?----------【增加一层间接层】是常用的解决方式。

定义:

为其他对象提供一种代理以控制(隔离、使用接口)对这个对象的访问。

结构:
结构

一个是真正的你要访问的对象(目标类),一个是代理对象,真正对象与代理对象实现同一个接口,先访问代理类再访问真正要访问的对象。

代理模式分为静态代理、动态代理。

静态代理:是由程序员创建或工具生成代理类的源码,再编译代理类。所谓静态也就是在程序运行前就已经存在代理类的字节码文件,代理类和委托类的关系在运行前就确定了。

动态代理:是在实现阶段不用关心代理类,而在运行阶段才指定哪一个对象。

组成:

抽象角色:通过接口或抽象类声明真实角色实现的业务方法。
代理角色:实现抽象角色,是真实角色的代理,通过真实角色的业务逻辑方法来实现抽象方法,并可以附加自己的操作。
真实角色:实现抽象角色,定义真实角色所要实现的业务逻辑,供代理角色调用。

要点总结:
  1. 【增加一层间接层】(代理的核心思想),是软件系统中对许多复杂问题的常见解法,在面向对象系统中,直接使用某些对象会带来很多问题,作为间接层的Proxy,便是解决这一问题的常用手法。

  2. 具体Proxy的实现手法,粒度都相差很大,有些可能是对单个对象做细粒度的控制,如copy-on-write技术,有些可能对组件模块提供抽象代理层,在架构层次对对象做proxy

  3. Proxy并不一定要去接口保持完全一致,只要能够实现间接控制,有时候损及一些透明性是可以接受的。

适用性:
   在需要用比较通用和复杂的对象指针代替简单的的指针的时候,使用代理模式。

   1、远程代理,也就是为一个对象在不同的地址空间提供局部代表。这样可以隐藏一个对象存在于不同地址空间的事实。

   2、虚拟代理,是根据需要创建开销很大的对象。通过它来存放实例化需要很长时间的真实对象。

   3、安全代理,用来控制真实对象访问的权限。

   4、智能指引,取代了简单的指针,它在访问对象时执行一些附加操作。
代码演示:

大话设计模式里面的例子:小王想追求小娟,但他不认识小娟。但他的朋友小林认识小娟,所以他通过让小林帮忙送礼物的方式追求小娟。

这里的小林就是我们的代理!

1.首先,我们实现一个女孩类:

class Girl{
public:
    Girl(char* name = ""):mName(name){}
    char* getName()
    {
        return mName;
    }
private:
    char* mName;
};

2.送礼物的接口

class GiveGift
{
public:
    virtual void GiveDolls() = 0;
    virtual void GiveFlowers() = 0;
    virtual void GiveChocolate() = 0;
};

3.送礼物实例类(小王)

class Puisuit : public GiveGift
{
public:
    Puisuit(Girl mm):mGirl(mm){}

    virtual void GiveDolls()
    {
        cout<<"送"<<mGirl.getName()<<"玩具!"<<endl;
    }

    virtual void GiveFlowers()
    {
        cout<<"送"<<mGirl.getName()<<"鲜花!"<<endl;
    }

    virtual void GiveChocolate()
    {
        cout<<"送"<<mGirl.getName()<<"巧克力!"<<endl;
    }
private:
    Girl mGirl;

};

4.送礼物代理类(小林)

class Proxy : public GiveGift
{
public:
    Proxy(Girl mm)
    {
        mPuisuit = new Puisuit(mm);
    }

    virtual void GiveDolls()
    {
        mPuisuit->GiveDolls();
    }

    virtual void GiveFlowers()
    {
        mPuisuit->GiveFlowers();
    }

    virtual void GiveChocolate()
    {
        mPuisuit->GiveChocolate();
    }
private:
    Puisuit* mPuisuit;

};

5.客户端代码:

#include <iostream>
#include "Proxy.h"

using namespace std;

int main()
{
    Girl mm("小娟");
    Proxy pro(mm);
    pro.GiveChocolate();
    pro.GiveDolls();
    pro.GiveFlowers();

    return 0;
}

适配器:Adapter

动机:

在软件系统中,由于应用环境的变化,常常需要将“一些现存的对象”放在新的环境中应用,但是新环境要求的接口是这些现存对象所不满足的。

如何应对这种迁移的变化?如何既能利用这些现有对象的良好实现,同时又能满足新应用环境所需要的接口?

定义:

将一个类的接口转换成客户希望的另外一个接口。Adapter模式使得原本由于接口不兼容而不能一起工作的那些类可以一起工作。
客户:需要调用我们的代码的对象。
Adapter模式的宗旨:保留现有类所提供的服务,向客户提供接口,以满足客户的期望。

结构:
结构
要点总结:

Adapter模式主要应用于“希望复用一些现存的类,但是接口又与复用环境要求不一致的情况,在【遗留代码复用】、【类库迁移】等方面非常有用。

采用对象组合方式,更符合松耦合精神。

Adapter模式实现方式灵活,不拘泥于Gof23的两种定义。比如将Adapter模式中的现存对象,作为新的接口方法参数,来达到适配目的。

代码演示:
//目标接口(新接口)
class ITarget{
public:
    virtual void process()=0;
};

//遗留接口(老接口)
class IAdaptee{
public:
    virtual void foo(int data)=0;
    virtual int bar()=0;
};

//遗留类型
class OldClass: public IAdaptee{
    //....
};

//对象适配器
class Adapter: public ITarget{ //继承
protected:
    IAdaptee* pAdaptee;//组合
    
public:
    
    Adapter(IAdaptee* pAdaptee){
        this->pAdaptee=pAdaptee;
    }
    
    virtual void process(){
        int data=pAdaptee->bar();
        pAdaptee->foo(data);        
    }
        
};

//类适配器
class Adapter: public ITarget,
               protected OldClass{ //多继承              
               
}
int main(){
    IAdaptee* pAdaptee=new OldClass();
    
    
    ITarget* pTarget=new Adapter(pAdaptee);
    pTarget->process();        
}

class stack{
    deqeue container;    
};

class queue{
    deqeue container;
    
};

中介者:Mediator

动机:

在软件构建过程中,经常会出现,多个对象相互关联交互的情况,对象之间常常会维持一种复杂的引用关系,如果遇到一些需求的更改,这种直接的引用关系会面临不断的变化。

在这种情况下,我们可以使用一个中介对象,来管理对象间的关联关系,避免相互交互的对象之间的紧耦合应用关系,从而更好的抵御变化。

定义:

用一个中介者对象来封装【封装变化】一系列的对象交互。中介者使得各对象不需要显式地相互引用【编译时依赖---->运行时依赖】,从而使其松散耦合【管理变化】,而且可以独立地改变它们之间的交互。

结构:
m,中介者
要点总结:

将多个对象间复杂的关联关系解耦,Mediator模式将多个对象间的控制逻辑进行集中管理,变“多个对象互相关联“为”多个对象和一个中介者关联”,简化了系统的维护,抵御了可能的变化。

随着控制逻辑的复杂化,Mediator具体对象的实现可能相当复杂,这时可以对Mediator对象进行分解处理。

Facade模式是解耦系统间(单向)的对象关联关系,Mediator模式是解耦系统内(双向)各个对象之间的关联关系。

代码演示:【参考资料】http://www.jianshu.com/p/65768cd62757
模式设计
public interface Mediator {
    void createMediator();
    void workAll();
}
public abstract class User {
    private Mediator mediator;

    public User(Mediator mediator) {
        this.mediator = mediator;
    }

    public Mediator getMediator(){
        return mediator;
    }

    public abstract void work();
}
public class User1 extends User {

    public User1(Mediator mediator) {
        super(mediator);
    }

    @Override
    public void work() {
        System.out.println("user1 exe!");
    }
}
public class User2 extends User {
    public User2(Mediator mediator) {
        super(mediator);
    }

    @Override
    public void work() {
        System.out.println("user2 exe!");
    }
}
public class MyMediator implements Mediator {
    private User user1;
    private User user2;

    public User getUser1() {
        return user1;
    }

    public User getUser2() {
        return user2;
    }

    @Override
    public void createMediator() {
        user1 = new User1(this);
        user2 = new User2(this);
    }

    @Override
    public void workAll() {
        user1.work();
        user2.work();
    }
}
public class Client {
    public static void main(String[] args) {
        Mediator mediator = new MyMediator();
        mediator.createMediator();
        mediator.workAll();
    }
}
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 200,667评论 5 472
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 84,361评论 2 377
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 147,700评论 0 333
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,027评论 1 272
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 62,988评论 5 361
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,230评论 1 277
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,705评论 3 393
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,366评论 0 255
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,496评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,405评论 2 317
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,453评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,126评论 3 315
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,725评论 3 303
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,803评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,015评论 1 255
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,514评论 2 346
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,111评论 2 341

推荐阅读更多精彩内容