工厂模式的定义:定义一个创建产品对象的工厂接口,将产品对象的实际创建工作推迟到具体子工厂类当中。
类图如下:
第11章介绍了C++11改进工厂模式的各种优化手段,一层一层地解耦泛化封装。
先看一个由直接依赖产生耦合性的例子:
#include <iostream>
using namespace std;
struct Base
{
virtual ~Base(){};
virtual void Func(){};
};
struct DerivedB : Base
{
void Func() override
{
cout << "call func in DerivedB" << endl;
}
};
struct DerivedC : Base
{
void Func() override
{
cout << "call func in DerivedC" << endl;
}
};
struct DerivedD : Base
{
void Func() override
{
cout << "call func in DerivedD" << endl;
}
};
// 类似代理模式
class A
{
public:
A(Base* interface) : m_inferfaceB(interface)
{
}
~A()
{
if (m_interfaceB != nullptr)
{
delete m_interfaceB;
m_interfaceB = nullptr;
}
}
void Func()
{
m_interfaceB->Func();
}
private:
// 依赖,是一种使用的关系
// 虽然依赖相对于继承关系属于对象关系中最弱的一种,但也会产生耦合性
Base* m_interfaceB;
};
int main()
{
A* a = new A(new DerivedB());
a->Func();
delete a;
return 0;
}
输出结果:
call func in DerivedB
A对象直接依赖于Base接口对象,会产生耦合性。看如下例子:
int main()
{
A* a = nullptr;
if (conditionB)
a = new A(new DerivedB());
else if (conditionC)
a = new A(new DerivedC());
else
a = new A(new DerivedD());
delete a;
return 0;
}
耦合性产生的原因在于A对象的创建直接依赖于new外部对象,这属于硬编码,使二者紧耦合。一种解决方法是通过工厂模式来创建对象。
struct Factory
{
static Base* Create(const string& condition)
{
if (condition == "B")
return new DerivedB();
else if (condition == "C")
return new DerivedC();
else if (condition == "D")
return new DerivedD();
else
return nullptr;
}
};
int main()
{
string condition = "B";
A *a = new A(Factory::Create(condition));
a->Func();
delete a;
return 0;
}
工厂模式避免了直接依赖,降低了耦合性,但是A对象仍然要依赖于一个工厂,通过工厂间接依赖于Base对象,没有彻底解耦。
控制反转(Inversion of Control, IoC),就是应用本身不负责依赖对象的创建和维护,而交给一个外部容器来负责。这样控制权就由应用转移到了IoC容器,实现了控制反转。IoC用来降低对象之间直接依赖产生的耦合性。具体做法是在IoC容器中配置这种依赖关系,有IoC容器来管理对象的依赖关系。
void IocSample()
{
// 通过IoC容器来配置A和Base对象的关系
IocContainer ioc;
// A与Base是依赖关系
ioc.RegisterType<A, DerivedB>("B");
ioc.RegisterType<A, DerivedC>("C");
ioc.RegisterType<A, DerivedD>("D");
// 由IoC容器区初始化A对象
A* a = ioc.Resolve<A>("B");
a->Func();
delete a;
}
通过依赖注入(Dependency Injection, DI)来将对象创建的依赖关系注入到目标类型的构造函数中。如将上例中A依赖于DerivedB的依赖关系注入到A的构造函数中。这样,A对象的创建不再依赖于工厂和Base对象,彻底解耦。
实现IoC容器需要解决3个问题:
(1)创建所有类型的对象(11.2)
(2)类型擦除(11.3, 11.4)
(3)创建依赖对象(11.4)
参考网址: