创建型设计模式(6种)学习

Linux服务器开发/后台架构师知识体系整理

创建型设计模式有: 共6种

  • 简单工厂模式(Simple Factory)
  • 工厂方法模式(Factory Method)
  • 抽象工厂模式(Abstract Factory)
  • 建造者模式(Builder)
  • 原型模式(Prototype)
  • 单例模式(Singleton)

简单工厂模式

功能:主要用于创建对象。新添加类时,不会影响以前的系统代码。核心思想是用一个工厂来根据输入的条件产生不同的类,然后根据不同类的virtual函数得到不同的结果。

优点: 适用于不同情况创建不同的类时

缺点: 客户端必须要知道基类和工厂类,耦合性差

模式结构

  • Factory:工厂角色负责实现创建所有实例的内部逻辑
  • Product:抽象产品角色是所创建的所有对象的父类,负责描述所有实例所共有的公共接口
  • ConcreteProduct:具体产品角色是创建目标,所有创建的对象都充当这个角色的某个具体类的实例。

在这里插入图片描述
C++举例:

//基类
class COperation
{
public:
    int m_nFirst;
    int m_nSecond;
    virtual double GetResult()
    {
        double dResult=0;
        return dResult;
    }
};
//加法
class AddOperation : public COperation
{
public:
    virtual double GetResult()
    {
        return m_nFirst+m_nSecond;
    }
};
//减法
class SubOperation : public COperation
{
public:
    virtual double GetResult()
    {
        return m_nFirst-m_nSecond;
    }
};

//工厂类
class CCalculatorFactory
{
public:
    static COperation* Create(char cOperator); //基类和工厂类是关联关系
};

COperation* CCalculatorFactory::Create(char cOperator)
{
    COperation *oper;
    switch (cOperator)
    {
    case '+':
        oper=new AddOperation();
        break;
    case '-':
        oper=new SubOperation();
        break;
    default:
        oper=new AddOperation();
        break;
    }
    return oper;
}

//客户端
int main()
{
    int a,b;
    cin>>a>>b;
    COperation * op=CCalculatorFactory::Create('-'); //静态函数直接调用
    op->m_nFirst=a;
    op->m_nSecond=b;
    cout<<op->GetResult()<<endl;
    return 0;
}

工厂方法模式(多态工厂模式)

功能:定义一个用于创建对象的接口,让子类决定实例化哪一个类。工厂方法使一个类的实例化延迟到其子类。

优点

  • 向客户隐藏了哪种具体产品将被实例化的细节,用户只需要关心所需产品对应的工厂,无须关心创建细节,无须知道具体产品类的类名。
  • 基于工厂角色和产品角色的多态性设计是工厂方法模式的关键。它能够使工厂可以自主确定创建何种产品对象,而如何创建这个对象的细节则完全封装在具体工厂内部。工厂方法模式之所以又被称为多态工厂模式,是因为所有的具体工厂类都具有同一抽象父类。
  • 系统中加新产品时,无须修改抽象工厂和抽象产品的接口,(但要修改客户端,以选择不同的具体工厂!),无须修改其他的具体工厂和产品,而只要添加一个具体工厂和具体产品即可。符合“开闭原则”。

缺点

  • 在添加新产品时,需要编写新的具体产品类,而且还要提供与之对应的具体工厂类,系统中类的个数将成对增加,一定程度上增加了系统复杂度,有更多的类需要编译和运行,会给系统带来一些额外的开销。
  • 由于考虑到系统的可扩展性,需要引入抽象层,在客户端代码中均使用抽象层进行定义,增加了系统的抽象性和理解难度,且在实现时可能需要用到DOM、反射等技术,增加了系统的实现难度。.

模式应用

JDBC中的工厂方法
在这里插入图片描述
举例

日志记录器:

某系统日志记录器要求支持多种日志记录方式,如文件记录、数据库记录等,且用户可以根据要求动态选择日志记录方式, 现使用工厂方法模式设计该系统。
在这里插入图片描述
C++举例

#include <string>
#include <iostream>
using namespace std;

//实例基类,相当于Product(为了方便,没用抽象)
class LeiFeng
{
public:
    virtual void Sweep()
    {
        cout<<"雷锋扫地"<<endl;
    }
};

//学雷锋的大学生,相当于ConcreteProduct(具体产品1)
class Student: public LeiFeng
{
public:
    virtual void Sweep()
    {
        cout<<"大学生扫地"<<endl;
    }
};

//学雷锋的志愿者,相当于ConcreteProduct(具体产品2)
class Volenter: public LeiFeng
{
public :
    virtual void Sweep()
    {
        cout<<"志愿者"<<endl;
    }
};

-----------------------------
//工场基类Creator
class LeiFengFactory
{
public:
    virtual LeiFeng* CreateLeiFeng() //返回值体现依赖关系
    {
        return new LeiFeng();
    }
};

//工场具体类1(创建大学生产品的具体工厂)
class StudentFactory : public LeiFengFactory
{
public :
    virtual LeiFeng* CreateLeiFeng() //返回值体现依赖关系
    {
        return new Student();
    }
};

//工场具体类2(创建志愿者产品的具体工厂)
class VolenterFactory : public LeiFengFactory
{
public:
    virtual LeiFeng* CreateLeiFeng()
    {
        return new Volenter(); //返回值体现依赖关系
    }
};

-----------------------------
//客户端
int main()
{
    LeiFengFactory *sf=new StudentFactory(); //由客户端选创建什么产品
    LeiFeng *s=sf->CreateLeiFeng();
    s->Sweep();
    delete s;
    delete sf;
    return 0;
}

抽象工厂模式(Kit模式)

功能:提供一个创建一系列相关或相互依赖对象的接口,而无需指定它们具体的类。

优点

  • 抽象工厂模式隔离了具体类的生成,使得客户并不需要知道什么被创建。由于这种隔离,更换一个具体工厂就变得容易。所有的具体工厂都实现了抽象工厂中定义的那些公共接口,因此只需改变具体工厂的实例,就可以在某种程度上改变整个软件系统的行为。另外,此模式可以实现高内聚低耦合的设计目的。
  • 当一个产品族中的多个对象被设计成一起工作时,它能够保证客户端始终只使用同一个产品族中的对象。这对一些需要根据当前环境来决定其行为的软件系统来说,很实用。
  • 增加新的具体工厂和产品族很方便,无须修改已有系统,符合“开闭原则”。

缺点

  • 在添加新的产品对象时,难以扩展抽象工厂来生产新种类的产品,这是因为在抽象工厂角色中规定了所有可能被创建的产品集合,要支持新种类的产品就意味着要对该接口进行扩展,而这将涉及到对抽象工厂角色及其所有子类的修改,显然会带来较大的不便。
  • 开闭原则的倾斜性(增加新的工厂和产品族容易,增加新的产品等级结构麻烦)。

模式应用

在很多软件系统中需要更换界面主题,要求界面中的按钮、文本框、背景色等一起发生改变时,可以使用抽象工厂模式进行设计。
在这里插入图片描述
C++举例

#include <string>
#include <iostream>
#include <vector>
using namespace std;

//用户抽象接口(抽象产品A)
class IUser
{
public :
    virtual void GetUser()=0;
    virtual void InsertUser()=0;
};

//部门抽象接口(抽象产品B)
class IDepartment
{
public:
    virtual void GetDepartment()=0;
    virtual void InsertDepartment()=0;
};

//ACCESS用户(抽象产品A的产品1)
class CAccessUser : public IUser
{
public:
    virtual void GetUser()
    {
        cout<<"Access GetUser"<<endl;
    }
    virtual void InsertUser()
    {
        cout<<"Access InsertUser"<<endl;
    }
};

//ACCESS部门(抽象产品B的产品1)
class CAccessDepartment : public IDepartment
{
public:
    virtual void GetDepartment()
    {
        cout<<"Access GetDepartment"<<endl;
    }
    virtual void InsertDepartment()
    {
        cout<<"Access InsertDepartment"<<endl;
    }
};

//SQL用户(抽象产品A的产品2)
class CSqlUser : public IUser
{
public:
    virtual void GetUser()
    {
        cout<<"Sql User"<<endl;
    }
    virtual void InsertUser()
    {
        cout<<"Sql User"<<endl;
    }
};

//SQL部门类(抽象产品B的产品2)
class CSqlDepartment: public IDepartment
{
public:
    virtual void GetDepartment()
    {
        cout<<"sql getDepartment"<<endl;
    }
    virtual void InsertDepartment()
    {
        cout<<"sql insertdepartment"<<endl;
    }
};

//抽象工厂
class IFactory
{
public:
    virtual IUser* CreateUser()=0;
    virtual IDepartment* CreateDepartment()=0;
};

//ACCESS工厂
class AccessFactory : public IFactory
{
public:
    virtual IUser* CreateUser()
    {
        return new  CAccessUser();
    }
    virtual IDepartment* CreateDepartment()
    {
        return new CAccessDepartment();
    }
};

//SQL工厂
class SqlFactory : public IFactory
{
public:
    virtual IUser* CreateUser()
    {
        return new  CSqlUser();
    }

    virtual IDepartment* CreateDepartment()
    {
        return new CSqlDepartment();
    }
};

//客户端:
int main()
{
    IFactory* factory= new SqlFactory();
    IUser* user=factory->CreateUser();
    IDepartment* depart = factory->CreateDepartment();

    user->GetUser();
    depart->GetDepartment();
    return 0;
}

建造者模式(生成器模式)

功能:将一个复杂对象的构建表示分离,使得同样的构建过程可以创建不同的表示。

优点

  • 客户端不必知道产品内部组成的细节,将产品本身与产品的创建过程解耦,使得相同的创建过程可以创建不同的产品对象。
  • 每一个具体建造者都独立,因此可以方便地替换具体建造者或增加新的具体建造者, 用户使用不同的具体建造者即可得到不同的产品对象
  • 可以更加精细地控制产品的创建过程 。将复杂产品的创建步骤分解在不同的方法中,使得创建过程更加清晰,也更方便使用程序来控制创建过程。
  • 增加新的具体建造者无须修改原有类库的代码,指挥者类针对抽象建造者类编程,系统扩展方便,符合“开闭”

缺点

  • 建造者模式所创建的产品一般具有较多的共同点,其组成部分相似,若产品之间的差异性很大,则不适合使用该模式,因此其使用范围受到一定限制。
  • 若产品的内部变化复杂,可能会导致需要定义很多具体建造者类来实现这种变化,导致系统变得很庞大。

模式应用

很多游戏软件中,地图包括天空、地面、背景等组成部分,人物角色包括人体、服装、装备等组成部分,可以使用建造者模式对其进行设计,通过不同的具体建造者创建不同类型的地图或人物。
在这里插入图片描述
举例: KFC套餐

套餐是一个复杂对象,一般包含主食(如汉堡、鸡肉卷等)和饮料(如果汁、 可乐等)等部分,不同的套餐有不同的组成部分,而KFC的服务员可以根据顾客的要求,一步一步装配这些组成部分,构造一份完整的套餐,然后返回给顾客。
在这里插入图片描述
C++举例

#include <string>
#include <iostream>
#include <vector>
using namespace std;

//最终的产品类
class Product 
{
private:
    vector<string> m_product;
public:
    void Add(string strtemp)
    {
        m_product.push_back(strtemp);
    }
    void Show()
    {
        vector<string>::iterator p=m_product.begin();
        while (p!=m_product.end())
        {
            cout<<*p<<endl;
            p++;
        }
    }
};

//建造者基类
class Builder
{
public:
    virtual void BuilderA()=0;
    virtual void BuilderB()=0;
    virtual Product* GetResult()=0;
};

//第一种建造方式
class ConcreteBuilder1 : public Builder
{
private:
    Product* m_product; //体现依赖关系
public:
    ConcreteBuilder1()
    {
        m_product=new Product();
    }
    virtual void BuilderA()
    {
        m_product->Add("one");
    }
    virtual void BuilderB()
    {
        m_product->Add("two");
    }
    virtual Product* GetResult()
    {
        return m_product;
    }
};

//第二种建造方式
class ConcreteBuilder2 : public Builder
{
private:
    Product * m_product;  //体现依赖关系
public:
    ConcreteBuilder2()
    {
        m_product=new Product();
    }
    virtual void BuilderA()
    {
        m_product->Add("A");
    }
    virtual void BuilderB()
    {
        m_product->Add("B");
    }
    virtual Product* GetResult()
    {
        return m_product;
    }
};

//指挥者类
class Direct
{
public:
    void Construct(Builder* temp) //构建一个使用Builder接口的对象
    {
        temp->BuilderA();
        temp->BuilderB();
    }
};

//客户端
int main()
{
    Direct *p=new Direct();
    Builder* b1=new ConcreteBuilder1();
    Builder* b2=new ConcreteBuilder2();

    p->Construct(b1);                 //调用第一种建造方式
    Product* pb1 = b1->GetResult();
    pb1->Show();

    p->Construct(b2);                 //调用第二种建造方式
    Product * pb2 = b2->GetResult();
    pb2->Show();
    return 0;
}

单例模式

功能:保证一个类仅有一个实例,并提供一个访问它的全局访问点。

优点

  • 提供了对唯一实例的受控访问。因为单例类封装了它的唯一实例,所以它可以严格控制客户怎样以及何时访问它,并为设计及开发团队提供了共享的概念。
  • 由于在系统内存中只存在一个对象,因此可以节约系统资源,对于一些需要频繁创建和销毁的对象,单例模式无疑可以提高系统的性能。
  • 允许可变数目的实例。我们可以基于单例模式进行扩展,使用与单例控制相似的方法来获得指定个数的对象实例。

缺点

  • 由于单例模式中没有抽象层,因此单例类的扩展有很大的困难。
  • 单例类的职责过重,在一定程度上违背了“单一职责原则”。因为单例类既充当了工厂角色,提供了工厂方法,同时又充当了产品角色,包含一些业务方法,将产品的创建和产品的本身的功能融合到一起。
  • 滥用单例将带来一些负面问题,如为了节省资源将数据库连接池对象设计为单例类,可能会导致共享连接池对象的程序过多而出现连接池溢出;现在很多面向对象语言(如Java、C#)的运行环境都提供了自动垃圾回收的技术,因此,如果实例化的对象长时间不被利用,系统会认为它是垃圾,会自动销毁并回收资源,下次利用时又将重新实例化,这将导致对象状态的丢失。

模式应用

一个具有自动编号主键的表可以有多个用户同时使用,但数据库中只能有一个地方分配下一个主键编号,否则会出现主键重复,因此该主键编号生成器必须具备唯一性,可以通过单例模式来实现。

在这里插入图片描述
举例

在OS中,打印池(Print Spooler)是一个用于管理打印任务的应用程序,通过打印池用户可以删除、中止或者改变打印任务的优先级,在一个系统中只允许运行一个打印池对象,如果重复创建打印池则抛出异常。现使用单例模式来模拟实现打印池的设计。

C++举例

懒汉式单例:

#include <iostream>
#include <string>
#include <vector>
using namespace std;

class Singelton
{
private:
    Singelton(){ }  //构造函数私有堵死了外界创建副本的可能!!!
    static Singelton* singel; //私有的静态全局变量来保存该类的唯一实例

public:
    static Singelton* GetInstance() //获得本类实例的唯一全局访问点
    {
        if(singel == NULL)
        {
            singel = new Singelton();
        }
        return singel;
    }

};
Singelton* Singelton::singel = NULL;//注意静态变量类外初始化

//客户端:
int main()
{
    Singelton* s1=Singelton::GetInstance();
    Singelton* s2=Singelton::GetInstance();
    if(s1 == s2)  //比较两次实例化后的结果是实例相同!!!
        cout<<"ok"<<endl;
    else
        cout<<"no"<<endl;
    return 0;
}

原型模式

功能:用原型实例指定创建对象的种类,并通过拷贝这些原型创建新的对象。原型模式其实就是从一个对象创建另外一个可定制的对象,而且不需知道任何创建的细节。

优点

一般在初始化的信息不发生变化的情况下,克隆是最好的办法,既隐藏了对象创建细节,又提高性能。其等于是不用重新初始化对象,而是动态地获得对象运行时的状态。

缺点

原型模式最主要的缺点是每一个类都必须配备一个克隆方法。配备克隆方法需要对类的功能进行通盘考虑,这对于全新的类来说不是很难,而对于已经有的类不一定很容易,特别是当一个类引用不支持序列化的间接对象,或者引用含有循环结构的时候。

模式应用
在这里插入图片描述
C++举例

#include<iostream>
#include <vector>
#include <string>
using namespace std;

//抽象基类
class Prototype  
{ 
private:
    string m_strName;

public: 
    Prototype(string strName){ m_strName = strName; }
    Prototype() { m_strName = " "; }
    void Show() 
    {
        cout<<m_strName<<endl;
    }
    virtual Prototype* Clone() = 0 ; //关键就在于这样一个抽象方法
} ; 

// class ConcretePrototype1 
class ConcretePrototype1 : public Prototype 
{ 
public: 
    ConcretePrototype1(string strName) : Prototype(strName){}
    ConcretePrototype1(){}

    virtual Prototype* Clone() 
    { 
        ConcretePrototype1 *p = new ConcretePrototype1() ; 
        *p = *this ;                         //复制对象 
        return p ; 
    } 
} ; 

// class ConcretePrototype2 
class ConcretePrototype2 : public Prototype 
{ 
public: 
    ConcretePrototype2(string strName) : Prototype(strName){}
    ConcretePrototype2(){}

    virtual Prototype* Clone() 
    { 
        ConcretePrototype2 *p = new ConcretePrototype2() ; 
        *p = *this ; //复制对象 
        return p ; 
    } 
} ; 


//客户端
int main()
{
    ConcretePrototype1* test = new ConcretePrototype1("小王");
    ConcretePrototype2* test2 = (ConcretePrototype2*)test->Clone();
    test->Show();
    test2->Show();
    return 0;
}

C/C++Linux服务器开发/后台架构师视频学习
面试题、学习资料、教学视频和学习路线图,免费分享有需要的可以自行添加学习交流群960994558

  • 2
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
学习Java中的设计模式可以按照以下步骤进行: 1. 了解基本概念:首先,你需要了解设计模式的基本概念和分类。设计模式是在特定情境下用于解决常见问题的经验性解决方案。常见的设计模式可以分为创建、结构和行为三类。 2. 学习常见的设计模式:掌握一些常用的设计模式是很重要的。一些经典的设计模式包括单例模式、工厂模式、观察者模式等。你可以通过阅读相关的书籍、教程或者参考资料来学习这些设计模式的原理和使用方法。 3. 实践应用:学习设计模式最好的方式是将其应用到实际项目中。尝试在你的Java项目中使用设计模式,以加深对其理解和运用能力。这样可以帮助你更好地理解设计模式的优势和适用场景。 4. 学习设计模式的源码:阅读一些开源项目或者框架的源码,特别是那些广泛使用了设计模式的项目。通过学习他们的代码,你会更好地理解设计模式在实际项目中的应用。 5. 参与讨论和交流:加入开发者社区或者参与设计模式相关的讨论和交流,与其他开发者分享你的经验和问题。这样可以帮助你与他人互动,深入了解设计模式的最佳实践和应用场景。 记住,设计模式是一工具,用于解决特定的问题。选择适当的设计模式需要根据具体的情况和需求来决定。不要过度使用设计模式,避免过度复杂化代码。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值