工厂模式
动机
在软件系统中,经常面临着创建对象的工作;由于需求的变化,需要创建的对象的具体类型经常变化。
如何应对这种变化?如何绕过常规的对象创建方法(new),提供一种封装机制来避免客户程序和这种具体对象创建工作的紧耦合?
代码示例:
MainForm方法调用Splitter将东西进行切分,有二进制文件切分、txt文件切分、图片文件切分、视频文件切分。
第一版:ISplitter * splitter= new BinarySplitter();这种写法依赖于具体类,违反依赖倒置原则(高层模块不应该依赖于低层模块,而是应该依赖于抽象。同时,抽象不应该依赖于具体实现,具体实现应该依赖于抽象。由编译时处理换成运行时处理)
// 抽象基类
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{
};
class MainForm : public Form
{
TextBox* txtFilePath;
TextBox* txtFileNumber;
ProgressBar* progressBar;
public:
void Button1_Click(){
ISplitter * splitter= new BinarySplitter();//依赖具体类
splitter->split();
}
};
第二版:具体调用工厂,MainForm不依赖于具体的类,而是依赖于抽象类和工厂基类。
class MainForm : public Form
{
SplitterFactory* factory;//工厂
public:
MainForm(SplitterFactory* factory){
this->factory=factory;
}
void Button1_Click(){
ISplitter * splitter=
factory->CreateSplitter(); //多态new
splitter->split();
}
};
ISplitterFactory
//抽象类
class ISplitter{
public:
virtual void split()=0;
virtual ~ISplitter(){}
};
//工厂基类
class SplitterFactory{
public:
virtual ISplitter* CreateSplitter()=0; // 创建对象
virtual ~SplitterFactory(){}
};
FileSplitter文件:几个具体的工厂继承自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();
}
};
工厂方法定义
定义一个用于创建对象的接口,让子类决定实例化哪一个类。 Factory Method使一个类的实例化延迟到其子类。
具体到上面的代码,用于创建对象的接口SplitterFactory,让子类(BinarySplitterFactory,TxtSplitterFactory等具体工厂)决定实例化哪一个类。
在下列情况下可以使用Factory Method模式:
• 当一个类不知道它所必须创建的对象的类的时候。
• 当一个类希望由它的子类来指定它所创建的对象的时候。
• 当类将创建对象的职责委托给多个帮助子类中的某一个,并且你希望将哪一个帮助子类是代理者这一信息局部化的时候。(classes delegate responsibility to one of several helper subclasses, and you want to localize the knowledge of which helper subclass is the delegate.)
原型模式
原型模式对工厂模式进行了一些方法合并,具体如下所示;
动机
在软件系统中,经常面临着某些结构复杂的对象的创建;由于需求的变化,这些对象经常面临着剧烈的变化,但是它们却拥有比较稳定一致的接口。
如何应对这种变化?如何向客户程序隔离出这些易变对象,从而使得依赖这些易变对象的客户程序不随着需求改变而改变?
代码示例
//抽象类
class ISplitter{
public:
virtual void split()=0;
virtual ISplitter* clone()=0; //通过克隆自己来创建对象
virtual ~ISplitter(){}
};
//具体类
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怎么用原型方法
class MainForm : public Form
{
ISplitter* prototype;//原型对象
public:
MainForm(ISplitter* prototype){
this->prototype=prototype;
}
void Button1_Click(){
ISplitter * splitter=
prototype->clone(); //克隆原型
splitter->split();
}
};
原型方法(Prototype Pattern)是一种创建型设计模式,其主要目的是通过复制现有对象来创建新对象,而不是通过实例化类。这样做可以避免直接使用构造函数创建对象,提高对象的创建效率,同时也使得对象的创建更加灵活。原型方法通常包含一个克隆方法,用于复制对象。
以下是一个简单的C++代码示例,演示了原型方法的实现:
#include <iostream>
#include <string>
// 抽象原型类
class Prototype {
public:
virtual Prototype* clone() const = 0;
virtual void printInfo() const = 0;
virtual ~Prototype() {}
};
// 具体原型类 A
class ConcretePrototypeA : public Prototype {
public:
Prototype* clone() const override {
return new ConcretePrototypeA(*this);
}
void printInfo() const override {
std::cout << "Concrete Prototype A" << std::endl;
}
};
// 具体原型类 B
class ConcretePrototypeB : public Prototype {
public:
Prototype* clone() const override {
return new ConcretePrototypeB(*this);
}
void printInfo() const override {
std::cout << "Concrete Prototype B" << std::endl;
}
};
int main() {
// 创建原型对象
Prototype* prototypeA = new ConcretePrototypeA();
Prototype* prototypeB = new ConcretePrototypeB();
// 克隆对象
Prototype* cloneA = prototypeA->clone();
Prototype* cloneB = prototypeB->clone();
// 打印信息
prototypeA->printInfo();
cloneA->printInfo();
prototypeB->printInfo();
cloneB->printInfo();
// 释放资源
delete prototypeA;
delete cloneA;
delete prototypeB;
delete cloneB;
return 0;
}
在上述示例中,Prototype 是抽象原型类,其中包含了 clone 和 printInfo 纯虚函数。ConcretePrototypeA 和 ConcretePrototypeB 是具体的原型类,分别实现了这两个函数。在 main 函数中,通过创建原型对象,然后克隆对象,最后打印信息,展示了原型方法的基本用法。
- 适用性
原型方法适用于那些需要频繁创建对象,且对象的创建成本较高或创建过程复杂的情况。通过克隆现有对象来创建新对象,可以提高效率、简化代码,并且灵活应对动态配置和变化。
- 原型模式和工厂方法的区别
创建方式:
原型模式通过克隆现有对象来创建新对象。
工厂方法模式通过实现工厂方法来由子类决定创建的具体产品。
关注点:
原型模式关注对象的复制。
工厂方法模式关注对象的创建。
灵活性:
原型模式更加灵活,允许在运行时动态选择复制的对象。
工厂方法模式更加固定,创建的对象由具体的子类工厂决定。
在实际应用中,选择使用哪种模式取决于需求和设计目标。原型模式更适合对象创建时变化不大、但需要频繁创建的情况,而工厂方法模式更适合在创建对象的类层次结构变化频繁时。