上篇文章,介紹了《大話設(shè)計(jì)模式》的第7章——代理模式。
本篇,來介紹《大話設(shè)計(jì)模式》的第8章——工廠方法模式。并通過C++代碼實(shí)現(xiàn)實(shí)例代碼的功能。
1 工廠方法模式
工廠方法模式(Factory Method):定義了一個(gè)創(chuàng)建對象的接口,讓子類決定實(shí)例化哪一個(gè)類。
工廠方法使一個(gè)類的實(shí)例化延遲到了子類。
工廠方法模式的類圖如下:
- Product:產(chǎn)品類,定義工廠方法所建立的對象的接口ConcreateProduct:具體產(chǎn)品類,實(shí)現(xiàn)了產(chǎn)品類的接口Creater:創(chuàng)造者類,聲明工廠方法,返回一個(gè)產(chǎn)品類的對象ConcreateCreater:具體創(chuàng)造者類,重新定義工廠方法,來返回一個(gè)具體產(chǎn)品
2 實(shí)例
背景:書中小故事,小菜的同班同學(xué)薛磊風(fēng),一直學(xué)雷鋒做好事幫助一個(gè)老人,但最近被車撞住院了,就委托其他同學(xué)繼續(xù)幫他做好事??梢允嵌鄠€(gè)同學(xué)都去,例如學(xué)雷鋒的大學(xué)1、學(xué)雷鋒的大學(xué)2、學(xué)雷鋒的大學(xué)n,當(dāng)然也可以是志愿者去。
題目:用代碼的形式來實(shí)現(xiàn)學(xué)雷鋒做好事
2.1 版本一:類繼承
版本一的實(shí)現(xiàn)比較簡單,僅使用類繼續(xù)的思想,讓學(xué)雷鋒的大學(xué)生,繼承雷鋒做好事的具體事項(xiàng)即可。
2.1.1 雷鋒類與大學(xué)生類
這里需要實(shí)現(xiàn)兩個(gè)類:
雷鋒類:定義一下做好事的具體方法,掃地、洗衣、買米
大學(xué)生類:直接繼承雷鋒類即可
// 雷鋒
class LeiFeng
{
public:
void Sweep()
{
printf("掃地n");
}
void Wash()
{
printf("洗衣n");
}
void BuyRice()
{
printf("買米n");
}
};
// 學(xué)雷鋒的大學(xué)生
class Undergraduate : LeiFeng
{
};
2.1.2 主函數(shù)
假設(shè)有3個(gè)學(xué)生在學(xué)雷鋒做好事。
首先,實(shí)例化三個(gè)學(xué)雷鋒的大學(xué)生,這里通過new是形式,返回在指針轉(zhuǎn)為(LeiFeng *)類型。
然后,就可以調(diào)用雷鋒做好事的方法來做好事了。
int main()
{
// 實(shí)例化三個(gè)學(xué)雷鋒的大學(xué)生
LeiFeng *student1 = (LeiFeng *)(new Undergraduate());
LeiFeng *student2 = (LeiFeng *)(new Undergraduate());
LeiFeng *student3 = (LeiFeng *)(new Undergraduate());
// 學(xué)雷鋒做好事
student1->Sweep();
student2->Wash();
student3->BuyRice();
delete student1;
delete student2;
delete student3;
return 0;
}
代碼運(yùn)行效果如下:
版本一中,僅實(shí)現(xiàn)了大學(xué)生學(xué)雷鋒做好事,如果社區(qū)志愿者也要學(xué)雷鋒做好事,就要?jiǎng)?chuàng)建志愿者類了,并且學(xué)雷鋒做好事,不需要知道具體是誰在做好事,因此可以使用簡單工廠來實(shí)例化具體要做好事的人,下面來看版本二。
2.2 版本二:簡單工廠模式
版本二,類圖如下:
- 學(xué)雷鋒的大學(xué)生類和學(xué)雷鋒的志愿者類來繼承雷鋒類簡單工廠類依賴于雷鋒類,簡單工廠的作用是實(shí)例化具體學(xué)雷鋒做好事的人
2.2.1 雷鋒類、學(xué)雷鋒類與簡單工廠類
這里需要實(shí)現(xiàn)兩個(gè)類:
- 雷鋒類(同版本一)學(xué)雷鋒的大學(xué)生類(同版本一)學(xué)雷鋒的志愿者類:直接繼承雷鋒類即可簡單雷鋒工廠類:根據(jù)參數(shù)類型來決定是實(shí)例化學(xué)雷鋒的大學(xué)生還是學(xué)雷雷鋒的志愿者
// 雷鋒
class LeiFeng
{
public:
void Sweep()
{
printf("掃地n");
}
void Wash()
{
printf("洗衣n");
}
void BuyRice()
{
printf("買米n");
}
};
// 學(xué)雷鋒的大學(xué)生
class Undergraduate : LeiFeng
{
};
// 學(xué)雷鋒的志愿者
class Volunteer : LeiFeng
{
};
// 學(xué)雷鋒的人物類型
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: // 學(xué)雷鋒的大學(xué)生
{
result = (LeiFeng *)(new Undergraduate());
break;
}
case XLF_TYPE_VOLUNTEER: // 學(xué)雷鋒的志愿者
{
result = (LeiFeng *)(new Volunteer());
break;
}
default:
break;
}
return result;
}
};
2.2.2 主函數(shù)
首先,實(shí)例化了一個(gè)簡單雷鋒工廠。
然后,給簡單工廠的CreateLeiFeng方法傳入學(xué)生參數(shù),得到學(xué)生對象,傳入志愿者參數(shù),得到志愿者對象。
最后,調(diào)用雷鋒做好事的方法來做好事了。
int main()
{
// 簡單雷鋒工廠
SimpleFactory simpleFactory;
// 實(shí)例化兩個(gè)學(xué)雷鋒的大學(xué)生和一個(gè)學(xué)雷鋒的志愿者
LeiFeng *student1 = simpleFactory.CreateLeiFeng(XLF_TYPE_STUDENT);
LeiFeng *student2 = simpleFactory.CreateLeiFeng(XLF_TYPE_STUDENT);
LeiFeng *volunteer1 = simpleFactory.CreateLeiFeng(XLF_TYPE_VOLUNTEER);
// 學(xué)雷鋒做好事
student1->Sweep();
student2->Wash();
volunteer1->BuyRice();
delete student1;
delete student2;
delete volunteer1;
return 0;
}
代碼運(yùn)行效果如下:
版本二運(yùn)用了簡單工廠方法,下面來看工廠方法是如何實(shí)現(xiàn)的。
2.3 版本三:工廠方法模式
版本三使用工廠方法模式,類圖如下:
- 學(xué)雷鋒的大學(xué)生類和學(xué)雷鋒的志愿者類來繼承雷鋒類學(xué)雷鋒的大學(xué)生工廠類和學(xué)雷鋒的志愿者工廠類來繼承雷鋒工廠類
注意工廠方法與簡單工廠的區(qū)分,工廠方法是與每一個(gè)產(chǎn)品對應(yīng)的,有幾個(gè)類型的產(chǎn)品,就有幾個(gè)類型的工廠。
工廠方法雖然看起來復(fù)雜了,但這種方式其實(shí)遵循的是開放-封閉原則,即如果要再新加一種學(xué)雷鋒的人物類型,同時(shí)再增加一個(gè)對應(yīng)的工廠方法類即可,不需要需要之前的代碼。而如果是使用簡單工廠,就要修改簡單工廠類了。
2.3.1 ?雷鋒類、學(xué)雷鋒類與學(xué)雷鋒的工廠方法類
這里需要實(shí)現(xiàn)六個(gè)類:
- 雷鋒類(同版本一)學(xué)雷鋒的大學(xué)生類(同版本一)學(xué)雷鋒的志愿者類(同版本二)雷鋒工廠類:虛基類,提供一個(gè)創(chuàng)建學(xué)雷鋒的對象的接口學(xué)雷鋒的大學(xué)生工廠類:繼承雷鋒工廠類,返回的是學(xué)雷鋒的大學(xué)生對象學(xué)雷鋒的志愿者工廠類:繼承雷鋒工廠類,返回的是學(xué)雷鋒的志愿者對象
// 雷鋒
class LeiFeng
{
public:
void Sweep()
{
printf("掃地n");
}
void Wash()
{
printf("洗衣n");
}
void BuyRice()
{
printf("買米n");
}
};
// 雷鋒工廠
class IFactory
{
public:
virtual LeiFeng *CreateLeiFeng()
{
return nullptr;
}
};
// 學(xué)雷鋒的大學(xué)生
class Undergraduate : LeiFeng
{
};
// 學(xué)雷鋒的大學(xué)生工廠
class UndergraduateFactory : IFactory
{
public:
LeiFeng *CreateLeiFeng()
{
return (LeiFeng *)(new Undergraduate());
}
};
// 學(xué)雷鋒的志愿者
class Volunteer : LeiFeng
{
};
// 學(xué)雷鋒的志愿者工廠
class VolunteerFactory : IFactory
{
public:
LeiFeng *CreateLeiFeng()
{
return (LeiFeng *)(new Volunteer());
}
};
2.3.2 主函數(shù)
首先,實(shí)例化了一個(gè)學(xué)雷鋒的大學(xué)生工廠。
然后,通過學(xué)雷鋒的大學(xué)生工廠來實(shí)例化學(xué)雷鋒的大學(xué)生對象,并調(diào)用學(xué)雷鋒做好事的接口做好事即可。
最后,學(xué)雷鋒的志愿者的邏輯與學(xué)雷鋒的大學(xué)生類似。
int main()
{
// 學(xué)雷鋒的大學(xué)生工廠
IFactory *undergraduateFactory = (IFactory *)(new UndergraduateFactory());
// 實(shí)例化兩個(gè)學(xué)雷鋒的大學(xué)
LeiFeng *student1 = undergraduateFactory->CreateLeiFeng();
LeiFeng *student2 = undergraduateFactory->CreateLeiFeng();
// 學(xué)雷鋒做好事
tudent1->Sweep();
student2->Wash();
delete student1;
delete student2;
delete undergraduateFactory;
// 學(xué)雷鋒的志愿者工廠
IFactory *volunteerFactory = (IFactory *)(new VolunteerFactory());
// 實(shí)例化一個(gè)學(xué)雷鋒的志愿者
LeiFeng *volunteer1 = volunteerFactory->CreateLeiFeng();
// 學(xué)雷鋒做好事
volunteer1->BuyRice();
delete volunteer1;
delete volunteerFactory;
return 0;
}
代碼運(yùn)行效果如下:
總結(jié)
本篇介紹了設(shè)計(jì)模式中的工廠方法模式,并通過學(xué)雷鋒做好事的實(shí)例,使用C++編程,來演示工廠方法模式的使用。