上篇文章,介绍了《大话设计模式》的第7章——代理模式。
本篇,来介绍《大话设计模式》的第8章——工厂方法模式。并通过C++代码实现实例代码的功能。
1 工厂方法模式
工厂方法模式(Factory Method):定义了一个创建对象的接口,让子类决定实例化哪一个类。
工厂方法使一个类的实例化延迟到了子类。
工厂方法模式的类图如下:
- Product:产品类,定义工厂方法所建立的对象的接口ConcreateProduct:具体产品类,实现了产品类的接口Creater:创造者类,声明工厂方法,返回一个产品类的对象ConcreateCreater:具体创造者类,重新定义工厂方法,来返回一个具体产品
2 实例
背景:书中小故事,小菜的同班同学薛磊风,一直学雷锋做好事帮助一个老人,但最近被车撞住院了,就委托其他同学继续帮他做好事。可以是多个同学都去,例如学雷锋的大学1、学雷锋的大学2、学雷锋的大学n,当然也可以是志愿者去。
题目:用代码的形式来实现学雷锋做好事
2.1 版本一:类继承
版本一的实现比较简单,仅使用类继续的思想,让学雷锋的大学生,继承雷锋做好事的具体事项即可。
2.1.1 雷锋类与大学生类
这里需要实现两个类:
雷锋类:定义一下做好事的具体方法,扫地、洗衣、买米
大学生类:直接继承雷锋类即可
// 雷锋
class LeiFeng
{
public:
void Sweep()
{
printf("扫地n");
}
void Wash()
{
printf("洗衣n");
}
void BuyRice()
{
printf("买米n");
}
};
// 学雷锋的大学生
class Undergraduate : LeiFeng
{
};
2.1.2 主函数
假设有3个学生在学雷锋做好事。
首先,实例化三个学雷锋的大学生,这里通过new是形式,返回在指针转为(LeiFeng *)类型。
然后,就可以调用雷锋做好事的方法来做好事了。
int main()
{
// 实例化三个学雷锋的大学生
LeiFeng *student1 = (LeiFeng *)(new Undergraduate());
LeiFeng *student2 = (LeiFeng *)(new Undergraduate());
LeiFeng *student3 = (LeiFeng *)(new Undergraduate());
// 学雷锋做好事
student1->Sweep();
student2->Wash();
student3->BuyRice();
delete student1;
delete student2;
delete student3;
return 0;
}
代码运行效果如下:
版本一中,仅实现了大学生学雷锋做好事,如果社区志愿者也要学雷锋做好事,就要创建志愿者类了,并且学雷锋做好事,不需要知道具体是谁在做好事,因此可以使用简单工厂来实例化具体要做好事的人,下面来看版本二。
2.2 版本二:简单工厂模式
版本二,类图如下:
- 学雷锋的大学生类和学雷锋的志愿者类来继承雷锋类简单工厂类依赖于雷锋类,简单工厂的作用是实例化具体学雷锋做好事的人
2.2.1 雷锋类、学雷锋类与简单工厂类
这里需要实现两个类:
- 雷锋类(同版本一)学雷锋的大学生类(同版本一)学雷锋的志愿者类:直接继承雷锋类即可简单雷锋工厂类:根据参数类型来决定是实例化学雷锋的大学生还是学雷雷锋的志愿者
// 雷锋
class LeiFeng
{
public:
void Sweep()
{
printf("扫地n");
}
void Wash()
{
printf("洗衣n");
}
void BuyRice()
{
printf("买米n");
}
};
// 学雷锋的大学生
class Undergraduate : LeiFeng
{
};
// 学雷锋的志愿者
class Volunteer : LeiFeng
{
};
// 学雷锋的人物类型
enum XUELEIFENG_TYPE
{
XLF_TYPE_STUDENT,
XLF_TYPE_VOLUNTEER,
XLF_TYPE_NUM,
};
// 简单雷锋工厂
class SimpleFactory
{
public:
LeiFeng *CreateLeiFeng(XUELEIFENG_TYPE type)
{
LeiFeng *result;
switch(type)
{
case XLF_TYPE_STUDENT: // 学雷锋的大学生
{
result = (LeiFeng *)(new Undergraduate());
break;
}
case XLF_TYPE_VOLUNTEER: // 学雷锋的志愿者
{
result = (LeiFeng *)(new Volunteer());
break;
}
default:
break;
}
return result;
}
};
2.2.2 主函数
首先,实例化了一个简单雷锋工厂。
然后,给简单工厂的CreateLeiFeng方法传入学生参数,得到学生对象,传入志愿者参数,得到志愿者对象。
最后,调用雷锋做好事的方法来做好事了。
int main()
{
// 简单雷锋工厂
SimpleFactory simpleFactory;
// 实例化两个学雷锋的大学生和一个学雷锋的志愿者
LeiFeng *student1 = simpleFactory.CreateLeiFeng(XLF_TYPE_STUDENT);
LeiFeng *student2 = simpleFactory.CreateLeiFeng(XLF_TYPE_STUDENT);
LeiFeng *volunteer1 = simpleFactory.CreateLeiFeng(XLF_TYPE_VOLUNTEER);
// 学雷锋做好事
student1->Sweep();
student2->Wash();
volunteer1->BuyRice();
delete student1;
delete student2;
delete volunteer1;
return 0;
}
代码运行效果如下:
版本二运用了简单工厂方法,下面来看工厂方法是如何实现的。
2.3 版本三:工厂方法模式
版本三使用工厂方法模式,类图如下:
- 学雷锋的大学生类和学雷锋的志愿者类来继承雷锋类学雷锋的大学生工厂类和学雷锋的志愿者工厂类来继承雷锋工厂类
注意工厂方法与简单工厂的区分,工厂方法是与每一个产品对应的,有几个类型的产品,就有几个类型的工厂。
工厂方法虽然看起来复杂了,但这种方式其实遵循的是开放-封闭原则,即如果要再新加一种学雷锋的人物类型,同时再增加一个对应的工厂方法类即可,不需要需要之前的代码。而如果是使用简单工厂,就要修改简单工厂类了。
2.3.1 雷锋类、学雷锋类与学雷锋的工厂方法类
这里需要实现六个类:
- 雷锋类(同版本一)学雷锋的大学生类(同版本一)学雷锋的志愿者类(同版本二)雷锋工厂类:虚基类,提供一个创建学雷锋的对象的接口学雷锋的大学生工厂类:继承雷锋工厂类,返回的是学雷锋的大学生对象学雷锋的志愿者工厂类:继承雷锋工厂类,返回的是学雷锋的志愿者对象
// 雷锋
class LeiFeng
{
public:
void Sweep()
{
printf("扫地n");
}
void Wash()
{
printf("洗衣n");
}
void BuyRice()
{
printf("买米n");
}
};
// 雷锋工厂
class IFactory
{
public:
virtual LeiFeng *CreateLeiFeng()
{
return nullptr;
}
};
// 学雷锋的大学生
class Undergraduate : LeiFeng
{
};
// 学雷锋的大学生工厂
class UndergraduateFactory : IFactory
{
public:
LeiFeng *CreateLeiFeng()
{
return (LeiFeng *)(new Undergraduate());
}
};
// 学雷锋的志愿者
class Volunteer : LeiFeng
{
};
// 学雷锋的志愿者工厂
class VolunteerFactory : IFactory
{
public:
LeiFeng *CreateLeiFeng()
{
return (LeiFeng *)(new Volunteer());
}
};
2.3.2 主函数
首先,实例化了一个学雷锋的大学生工厂。
然后,通过学雷锋的大学生工厂来实例化学雷锋的大学生对象,并调用学雷锋做好事的接口做好事即可。
最后,学雷锋的志愿者的逻辑与学雷锋的大学生类似。
int main()
{
// 学雷锋的大学生工厂
IFactory *undergraduateFactory = (IFactory *)(new UndergraduateFactory());
// 实例化两个学雷锋的大学
LeiFeng *student1 = undergraduateFactory->CreateLeiFeng();
LeiFeng *student2 = undergraduateFactory->CreateLeiFeng();
// 学雷锋做好事
tudent1->Sweep();
student2->Wash();
delete student1;
delete student2;
delete undergraduateFactory;
// 学雷锋的志愿者工厂
IFactory *volunteerFactory = (IFactory *)(new VolunteerFactory());
// 实例化一个学雷锋的志愿者
LeiFeng *volunteer1 = volunteerFactory->CreateLeiFeng();
// 学雷锋做好事
volunteer1->BuyRice();
delete volunteer1;
delete volunteerFactory;
return 0;
}
代码运行效果如下:
总结
本篇介绍了设计模式中的工厂方法模式,并通过学雷锋做好事的实例,使用C++编程,来演示工厂方法模式的使用。