前提:“对象创建”模式

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

典型模式(表现最为突出)

工厂方法模式:Factory Method
抽象工厂模式:Abstract Factory
原型模式:Prototype
创建者模式:Builder

一:工厂方法模式

(一)概念

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

(二)动机

在软件系统中,经常面临这创建对象的工作;由于需求的变化,需要创建的对象的具体类型经常变化。
如何应对这种变化?如何绕过常规的对象创建方法(new),提供一种“封装机制”来避免客户程序和这种“具体对象创建工作”的紧耦合。

(三)代码讲解(同文件分割)问题提出

1.原代码

class FileSplitter
{
public:
void split(){
//...
}
};
class MainForm : public Form
{
TextBox* txtFilePath; //文件路径
TextBox* txtFileNumber; //希望分割的个数
ProgressBar* progressBar; public:
void Button1_Click(){
//收集到用户输入的参数信息
string filePath = txtFilePath->getText();
int number = atoi(txtFileNumber->getText().c_str());
//传递给FileSplitter,让该类去分割文件
FileSplitter splitter(filePath, number, progressBar);
//进行分割
splitter.split(); }
};
动态看待问题,上面使用了具体细节类,是静态特质,定死了,我们应该去判断业务有没有需求的变化,是不是只需要文件分割。比如我们这里有变化,支持二进制,图片,视频,文本分割...,此时我们应该将他声明为抽象基类来使用

2.改进为抽象基类

class ISplitter{
public:
virtual void split()=;
virtual ~ISplitter(){}
}; class BinarySplitter : public ISplitter{ }; class TxtSplitter: public ISplitter{ }; class PictureSplitter: public ISplitter{ }; class VideoSplitter: public ISplitter{ };
class MainForm : public Form
{
TextBox* txtFilePath;
TextBox* txtFileNumber;
ProgressBar* progressBar; public:
void Button1_Click(){ ISplitter * splitter=
new BinarySplitter();//依赖具体类
splitter->split(); }
};
依赖倒置原则:应该去依赖抽象,而不是依赖实现细节
        ISplitter * splitter=  //依赖抽象
new BinarySplitter();//依赖具体类,依赖细节
代码当中哪怕只出现一处细节依赖,其他都是抽象依赖也解决不了问题,将该依赖倒置原则打破了,所以在编译时还是要依赖BinarySplitter才能编译通过
通过“对象创建”模式绕开new,来避免对象创建(new)过程中所导致的紧耦合(依赖具体类),从而支持对象创建的稳定。它是接口抽象之后的第一步工作。

(三)代码讲解(同文件分割)问题解决

1.改进一

我们可以使用一个方法来返回一个对象,避免直接使用new创建
class SplitterFactory : public ISplitter{
public:
ISplitter* CreateSplitter()
{
return new BinarySplitter();  //这里还是个依赖(都是编译时)
}
};
class MainForm : public Form
{
TextBox* txtFilePath;
TextBox* txtFileNumber;
ProgressBar* progressBar; public:
void Button1_Click(){ SplitterFatory factory;  //这里是个依赖
ISplitter * splitter=
factory.CreateSplitter();
splitter->split(); }
};
没有从根本解决问题,间接依赖关系,还是依赖,没有绕开这个问题。
我们可以将编译时依赖转运行时依赖,如何做:找虚函数

2.改进二:使用虚函数

class ISplitter{
public:
virtual void split()=;
virtual ~ISplitter(){}
virtaul ISplitter* CreateSplitter()=;
};
        SplitterFatory* factory;    //未来?从哪来?看下面3,可以是下面具体工厂
ISplitter * splitter=
factory->CreateSplitter(); //交给未来

3改进三:将工厂基类和抽象类解耦

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

4.根据具体类创建一些类的具体工厂

//具体类
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();
}
};
每个具体的类都有对应的具体工厂,所以我们上面的未来就有着落了

5.改进四:将未来变为字段,可以实现构造从外界传递数据修改未来

class MainForm : public Form
{
SplitterFactory* factory;//工厂,抽象基类 public: MainForm(SplitterFactory* factory){
this->factory=factory;
} void Button1_Click(){ ISplitter * splitter=
factory->CreateSplitter(); //多态new,通过虚函数
splitter->split(); }
};
MainForm 没有具体类的依赖了,将变化赶出去到每一个局部区域

5.程序调用:将变化赶到调用处

void proceed()
{
TxtSplitterFactory* fact=new TxtSplitterFactory();
MainForm* mf =new MainForm(fact);
}

(四)代码分析

class MainForm : public Form
{
SplitterFactory* factory;//工厂 public: MainForm(SplitterFactory* factory){
this->factory=factory;
} void Button1_Click(){ ISplitter * splitter=
factory->CreateSplitter(); //多态new splitter->split(); }
};

MainForm

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

抽象类和工厂基类

//具体类
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();
}
};

具体类和具体工厂

依赖关系:

MainForm只依赖抽象类和工厂基类,抽象的
而不去依赖具体类和具体工厂,这些具体实例会被隔离到初始化方法中,像是main方法

(五)模式定义

定义一个用于创建对象的接口,让子类决定实例化哪一个类。

Factory Method使得一个类的实例化延迟(目的:解耦,手段:虚函数)到子类。

                                                                    --《设计模式》Gof

(六)类图(结构)

(七)要点总结

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

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

原来我们需要不断修改new对象:更改
        ISplitter * splitter=
new BinarySplitter();//依赖具体类
现在我们只需要扩展子类和子类工厂即可,而MainForm不动,是稳定的:不更改可扩展
        ISplitter * splitter=
factory->CreateSplitter(); //多态new,通过虚函数

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

在软件中,可以通过将new封装到工厂类的create函数中,并且将工厂类抽象出一个基类,实现new的多态性。这样可以保证对象构建函数的复用,实现将变化集中的目的。 

(八)案例实现:工厂生产水果

1.抽象类和抽象工厂实现

class Fruit
{
public:
virtual void sayName() = ;
}; class FruitFactory
{
public:
virtual Fruit* getFruit() = ;
};

2.具体类和具体工厂实现

class Apple :public Fruit
{
public:
void sayName()
{
cout << "an apple you get" << endl;
}
}; class Banana :public Fruit
{
public:
void sayName()
{
cout << "an banana you get" << endl;
}
}; class AppleFactory :public FruitFactory
{
public:
virtual Fruit* getFruit()
{
return new Apple();
}
}; class BananaFractory :public FruitFactory
{
public:
virtual Fruit* getFruit()
{
return new Banana();
}
};

3.结果测试

void main()
{
Fruit* f = NULL;
FruitFactory* ff = new AppleFactory();
f = ff->getFruit();
f->sayName();
system("pause");
return;
}

设计模式---对象创建模式之工厂方法模式(Factory Method)的更多相关文章

  1. PYTHON设计模式,创建型之工厂方法模式

    我感觉和上一个差不多,可能不要动最要的地方吧... #!/usr/bin/evn python #coding:utf8 class Pizza(object): def prepare(self, ...

  2. 浅谈C++设计模式之工厂方法(Factory Method)

    为什么要用设计模式?根本原因是为了代码复用,增加可维护性. 面向对象设计坚持的原则:开闭原则(Open Closed Principle,OCP).里氏代换原则(Liskov Substitution ...

  3. Java设计模式(2)——创建型模式之工厂方法模式(Factory Method)

    一.概述 上一节[简单工厂模式]介绍了通过工厂创建对象以及简单的利弊分析:这一节来看看工厂方法模式对类的创建 工厂方法模式: 工厂方法与简单工厂的不同,主要体现在简单工厂的缺点的改进: 工厂类不再负责 ...

  4. JAVA设计模式(01):创建型-工厂模式【工厂方法模式】(Factory Method)

    简单工厂模式尽管简单,但存在一个非常严重的问题.当系统中须要引入新产品时,因为静态工厂方法通过所传入參数的不同来创建不同的产品,这必然要改动工厂类的源码,将违背"开闭原则".怎样实 ...

  5. 设计模式学习之工厂方法(Factory Method,创建型模式)(2)

    接着上一讲中的简单工厂继续讲解,假如我们有了需要采集新的水果梨子,如果我们使用简单工厂中的方式的话,就会新增一个Pear类,然后实现Fruit类,然后修改FruitFactory类中获取实例的方法 g ...

  6. 设计模式的征途—3.工厂方法(Factory Method)模式

    上一篇的简单工厂模式虽然简单,但是存在一个很严重的问题:当系统中需要引入新产品时,由于静态工厂方法通过所传入参数的不同来创建不同的产品,这必定要修改工厂类的源代码,将违背开闭原则.如何实现新增新产品而 ...

  7. Java设计模式之【工厂模式】(简单工厂模式,工厂方法模式,抽象工厂模式)

    Java设计模式之[工厂模式](简单工厂模式,工厂方法模式,抽象工厂模式) 工厂模式出现的原因 在java中,创建一个对象最简单的方法就是使用new关键字.但在一些复杂的业务逻辑中,创建一个对象不只需 ...

  8. Java设计模式学习记录-简单工厂模式、工厂方法模式

    前言 之前介绍了设计模式的原则和分类等概述.今天开启设计模式的学习,首先要介绍的就是工厂模式,在介绍工厂模式前会先介绍一下简单工厂模式,这样由浅入深来介绍. 简单工厂模式 做法:创建一个工厂(方法或类 ...

  9. Javascript设计模式理论与实战:工厂方法模式

    本文从简单工厂模式的缺点说起,引入工厂方法模式,介绍的工厂方法模式的基本知识,实现要点和应用场景,最后举例进行说明工厂方法模式的应用.在之前的<Javascript设计模式理论与实战:简单工厂模 ...

随机推荐

  1. 详解Windows不重启使环境变量修改生效(经典)

    在“我的电脑”->“属性”->“高级”->“环境变量”中增加或修改环境变量后,需重启系统才能使之生效.有没有什么方法可让它即时生效呢?下面介绍一种方法: 以修改环境变量“PATH”为 ...

  2. Kivy crash 中文教程 实例入门 1. 第1个应用 Kivy App (Making a simple App)

    1.  空白窗口 在 PyCharm 中创建一个名为 TutorialApp 的项目,然后在该项目中新建了个名为 tutorial_app.py 的 Python 源文件,在 PyCharm 的代码编 ...

  3. loadrunner基础学习笔记三

    运行时设置: 打开运行时设置:任务窗格中-选择回放-点击运行时设置按钮  1 重复执行次数:=2 2 步:控制迭代时间间隔 3 日志设置:指出要在运行测试期间记录的信息量 4 思考时间:可以在cont ...

  4. XQN number format

    Q Numbers FormatAn XQN format number is an 1+X+N bit twos complement binary number; a sign bitfollow ...

  5. 使用libcurl 发送post请求

    SendHttpPost(string& strUrl, string& strPost, string& strResponse, int nTimeOut) { CURLc ...

  6. BZOJ1299[LLH邀请赛]巧克力棒——Nim游戏+搜索

    题目描述 TBL和X用巧克力棒玩游戏.每次一人可以从盒子里取出若干条巧克力棒,或是将一根取出的巧克力棒吃掉正整数长度.TBL先手两人轮流,无法操作的人输. 他们以最佳策略一共进行了10轮(每次一盒). ...

  7. ansible创建vmware虚拟机

    环境:vmware 虚拟化需求:如果业务部门一次提几十台甚至几百台虚拟机需求,一个个的手动创建肯定耗时 使用ansible vmware_guest 创建虚拟机,避免手动一台一台创建的纯手工 工作废话 ...

  8. 矩阵游戏 HYSBZ - 1059(最大流)

    1059: [ZJOI2007]矩阵游戏 Time Limit: 10 Sec  Memory Limit: 162 MBSubmit: 6266  Solved: 3065[Submit][Stat ...

  9. QAU 18校赛 J题 天平(01背包 判断能否装满)

    问题 J: 天平 时间限制: 1 Sec  内存限制: 128 MB提交: 36  解决: 9[提交][状态][讨论版][命题人:admin] 题目描述 天平的右端放着一件重量为w的物品.现在有n个重 ...

  10. poj 2236 Wireless Network (并查集)

    链接:http://poj.org/problem?id=2236 题意: 有一个计算机网络,n台计算机全部坏了,给你两种操作: 1.O x 修复第x台计算机 2.S x,y 判断两台计算机是否联通 ...