最近在看設計模式(Head First那本),這本書寫的很不錯,唯一的缺點是整本書都是用JAVA語言寫的,JAVA雖然和C++一樣都是面向對象的,但是有些術語還是不一樣的,例如JAVA裡面有“接口”這個術語,而在C++裡面沒有。不過好在這些模式C++應該都可以實現。
在第一章的策略模式中,講到鴨子這個例子,這是一個很經典的例子,相信在軟件開發中一定能經常遇到。把不變的東西和變化的東西進行分離,這樣在以後的修改或添加新功能時能節省不少時間。下面我來嘗試下用C++實現策略模式,由於能力有限,其中可能存在一些問題,歡迎指出提出修改意見,在此虛心接受。
下面就開始說鴨子吧。這裡為了簡化起見,只假設有fly這個需要變化的情況,至於鴨子會不會叫暫時假定都會。
按照書上的描述,要把duck和fly進行分離,JAVA中是把fly作為接口,在C++中我把fly作為一個抽象類,和書中描述的一樣,這兩個類是平級的。duck類中有鴨子的一些共有的不變的行為,fly類中包含兩個抽象函數來設置飛行與否,除了這兩個類以外,我還加入cn_duck(中國鴨子)這個類,以及duck_fly這個類,中國鴨子是鴨子的一種,姑且不論實際情況會不會飛,反正我們想讓它飛他就飛了,duck_fly是把fly類裡面的虛函數進行具體化。具體類圖結構如下:
見圖1
由上圖可以看到,cn_duck類繼承duck類,故其能夠調用duck類中的方法,同時duck類與fly類有接口通信,這樣cn_duck類也能調用fly類中的方法,前提是要給cn_duck類傳遞一個duck_fly類的對象。當需要添加更多的飛行時,可以在和duck_fly類平級上進行添加類,例如添加一個火箭飛行類。而在添加鴨子類型時,可以在cn_duck類平級上進行添加類,例如添加一個美國鴨子。這就是我理解的策略模式。不需要修改duck類,在用其他方法飛行時,也不需要修改fly類(除非添加除了飛行方法但是和飛行有關的行為,例如把鴨子翅膀添加到飛行中去,中國鴨子鋼翅膀nb鴨子)。下面給出工程的代碼,歡迎拍磚。
view plaincopy to clipboardprint?
//duck.h
#include "fly.h"
class duck
{
public:
void quack();
void swim();
virtual void display();
fly *fy;
void set_fly(fly *fy);
};
//duck.h
#include "fly.h"
class duck
{
public:
void quack();
void swim();
virtual void display();
fly *fy;
void set_fly(fly *fy);
};
view plaincopy to clipboardprint?
//duck.cpp
#include "duck.h"
#include <iostream>
using namespace std;
void duck::quack()
{
cout<<"我在呱呱叫"<<endl;
}
void duck::swim()
{
cout<<"我在游泳"<<endl;
}
void duck::display()
{
cout<<"我是普通鴨子黃色嘴巴"<<endl;
}
void duck::set_fly(fly *fy)
{
this->fy=fy;
}
//duck.cpp
#include "duck.h"
#include <iostream>
using namespace std;
void duck::quack()
{
cout<<"我在呱呱叫"<<endl;
}
void duck::swim()
{
cout<<"我在游泳"<<endl;
}
void duck::display()
{
cout<<"我是普通鴨子黃色嘴巴"<<endl;
}
void duck::set_fly(fly *fy)
{
this->fy=fy;
}
view plaincopy to clipboardprint?
//fly.h
#ifndef FLY_EGG
#define FLY_EGG
class fly
{
public:
virtual void can_fly()=0;
virtual void no_fly()=0;
virtual void fly_way()=0;
};
#endif
//fly.h
#ifndef FLY_EGG
#define FLY_EGG
class fly
{
public:
virtual void can_fly()=0;
virtual void no_fly()=0;
virtual void fly_way()=0;
};
#endif
view plaincopy to clipboardprint?
//duck_fly.h
#include <iostream>
#include "fly.h"
using namespace std;
class duck_fly: public fly
{
public:
void can_fly()
{
cout<<"duck fly!"<<endl;
}
void no_fly()
{
cout<<"duck not fly!"<<endl;
}
void fly_way()
{
cout<<"fly with wings"<<endl;
}
};
//duck_fly.h
#include <iostream>
#include "fly.h"
using namespace std;
class duck_fly: public fly
{
public:
void can_fly()
{
cout<<"duck fly!"<<endl;
}
void no_fly()
{
cout<<"duck not fly!"<<endl;
}
void fly_way()
{
cout<<"fly with wings"<<endl;
}
};
view plaincopy to clipboardprint?
//cn_duck.h
#include "duck.h"
class cn_duck:public duck
{
public:
cn_duck();
void display();
};
//cn_duck.h
#include "duck.h"
class cn_duck:public duck
{
public:
cn_duck();
void display();
};
view plaincopy to clipboardprint?
//cn_duck.cpp
#include "cn-duck.h"
#include <iostream>
using namespace std;
cn_duck::cn_duck()
{
fy=NULL;
}
void cn_duck::display()
{
cout<<"我是紅嘴巴"<<endl;
}
//cn_duck.cpp
#include "cn-duck.h"
#include <iostream>
using namespace std;
cn_duck::cn_duck()
{
fy=NULL;
}
void cn_duck::display()
{
cout<<"我是紅嘴巴"<<endl;
}
view plaincopy to clipboardprint?
//main.cpp
#include "cn-duck.h"
#include "duck_fly.h"
int main()
{
//給定接口,表明是duck飛
duck_fly *df=new duck_fly();
cn_duck cd;
cd.set_fly(df);//設定會飛
cd.fy->can_fly();//調用duck_fly裡的飛行
cd.fy->fly_way();//調用飛行方法
return 0;
}
//main.cpp
#include "cn-duck.h"
#include "duck_fly.h"
int main()
{
//給定接口,表明是duck飛
duck_fly *df=new duck_fly();
cn_duck cd;
cd.set_fly(df);//設定會飛
cd.fy->can_fly();//調用duck_fly裡的飛行
cd.fy->fly_way();//調用飛行方法
return 0;
}
上面就是我的理解,歡迎提出改進意見,當然程序有點問題,就是如果沒有把duck_fly對象給cn_duck時,程序沒有提示,但是會報錯,不過按情理來說報錯也是正常的,鴨子不會非肯定報錯。
下面是程序運行界面: