close
雙分派實例說明
參考《設計模式之禪》P371的例子,但是改成 C++。
考慮以下例子:
演員演電影角色,一個演員可以扮演多個角色。角色分成功夫角色和諧星角色,演員有年紀大的演員和年輕的演員。
角色
class CRole //角色
{
};
class CKungFu : public CRole //功夫角色
{
};
class CFunny : public CRole //諧星角色
{
};
演員
//宣告
class CAbsActor //演員
{
public:
virtual void Act(CRole *pRole);
virtual void Act(CKungFu *pKungFu);
virtual void Act(CFunny *pFunny);
};
class CYoung : public CAbsActor //年輕演員
{
public:
virtual void Act(CKungFu *pKungFu);
virtual void Act(CFunny *pFunny);
};
class COld : public CAbsActor //年紀大演員
{
public:
virtual void Act(CKungFu *pKungFu);
virtual void Act(CFunny *pFunny);
};
//定義
//CAbsActor
void CAbsActor::Act(CRole *pRole)
{
cout<<"只要是演員就可以演各種角色"<<endl;
}
void CAbsActor::Act(CKungFu *pKungFu)
{
cout<<"演功夫角色"<<endl;
}
void CAbsActor::Act(CFunny *pFunny)
{
cout<<"演諧星角色"<<endl;
}
//CYoung
void CYoung::Act(CKungFu *pKungFu)
{
cout<<"年輕人最喜歡演功夫"<<endl;
}
void CYoung::Act(CFunny *pFunny)
{
cout<<"年輕人愛搞笑"<<endl;
}
//COld
void COld::Act(CKungFu *pKungFu)
{
cout<<"年紀大演功夫很累"<<endl;
}
void COld::Act(CFunny *pFunny)
{
cout<<"年紀大笑點很怪"<<endl;
}
主程式
//主程式
int main()
{
CAbsActor *pActor = new COld; //定義一個年紀大的演員
CRole *pRole = new CKungFu; //定義一個功夫角色
pActor->Act(pRole); //演戲
delete pActor;
delete pRole;
system("pause");
return 0;
}
這裡特別要注意的是,我都是用父類別宣告,因為在專案裡還是比較常遇到用父類別當參數的情況。
執行結果:只要是演員就可以演各種角色
但我其實希望的結果是「年紀大演功夫很累」,也就是執行COld::Act(CKungFu *pKungFu),而不是CAbsActor::Act(CRole *pRole)。會造成這樣是因為宣告時使用CAbsActor和CRole,所以會執行CAbsActor::Act(CRole *pRole)。
我們的希望是CAbsActor::Act會根據傳進來的CRole是哪個類別而做不同的事,所以改成這樣?
角色
//角色
class CRole //角色
{
public:
enum{ROLE, KUNGFU, FUNNY};
int m_nKind; //區分子類別
CRole(){m_nKind = ROLE;}
};
class CKungFu : public CRole //功夫角色
{
public:
CKungFu(){m_nKind = KUNGFU;}
};
class CFunny : public CRole //諧星角色
{
public:
CFunny(){m_nKind = FUNNY;}
};
演員
//宣告
class CAbsActor //演員
{
public:
virtual void Act(CRole *pRole);
};
class CYoung : public CAbsActor //年輕演員
{
public:
virtual void Act(CRole *pRole);
};
class COld : public CAbsActor //年紀大演員
{
public:
virtual void Act(CRole *pRole);
};
//定義
//CAbsActor
void CAbsActor::Act(CRole *pRole)
{
//根據子類別不同做不同的事
if(pRole->m_nKind == CRole::ROLE)
cout<<"只要是演員就可以演各種角色"<<endl;
else if(pRole->m_nKind == CRole::KUNGFU)
cout<<"演功夫角色"<<endl;
else if(pRole->m_nKind == CRole::FUNNY)
cout<<"演諧星角色"<<endl;
}
//CYoung
void CYoung::Act(CRole *pRole)
{
if(pRole->m_nKind == CRole::ROLE)
cout<<"只要是演員就可以演各種角色"<<endl;
else if(pRole->m_nKind == CRole::KUNGFU)
cout<<"年輕人最喜歡演功夫"<<endl;
else if(pRole->m_nKind == CRole::FUNNY)
cout<<"年輕人愛搞笑"<<endl;
}
//COld
void COld::Act(CRole *pRole)
{
if(pRole->m_nKind == CRole::ROLE)
cout<<"只要是演員就可以演各種角色"<<endl;
else if(pRole->m_nKind == CRole::KUNGFU)
cout<<"年紀大演功夫很累"<<endl;
else if(pRole->m_nKind == CRole::FUNNY)
cout<<"年紀大笑點很怪"<<endl;
}
主程式不變
int main()
{
CAbsActor *pActor = new COld; //定義一個年紀大的演員
CRole *pRole = new CKungFu; //定義一個功夫角色
pActor->Act(pRole); //演戲
delete pActor;
delete pRole;
system("pause");
return 0;
}
執行結果:「年紀大演功夫很累」。
是啦,是有達到需求,但是3個長得很像的if-else如果要改一定會很頭大。所以這種方式完完全全不能考慮。
這裡的問題在於,連act都必須因為Role不同而做不同的act。這不是光用抽象就可以辦到的,因此考慮雙分派的做法。
角色
class CRole //角色
{
public:
//演員要扮演的角色
virtual void Accept(CAbsActor *pActor)=0;
};
class CKungFu : public CRole //功夫角色
{
virtual void Accept(CAbsActor *pActor);
};
class CFunny : public CRole //諧星角色
{
virtual void Accept(CAbsActor *pActor);
};
void CFunny::Accept(CAbsActor *pActor)
{
pActor->Act(this);
}
void CKungFu::Accept(CAbsActor *pActor)
{
pActor->Act(this);
}
演員
class CAbsActor //演員
{
public:
virtual void Act(CRole *pRole);
virtual void Act(CKungFu *pKungFu);
virtual void Act(CFunny *pFunny);
};
class CYoung : public CAbsActor //年輕演員
{
public:
virtual void Act(CKungFu *pKungFu);
virtual void Act(CFunny *pFunny);
};
class COld : public CAbsActor //年紀大演員
{
public:
virtual void Act(CKungFu *pKungFu);
virtual void Act(CFunny *pFunny);
};
//定義
//CAbsActor
void CAbsActor::Act(CRole *pRole)
{
cout<<"只要是演員就可以演各種角色"<<endl;
}
void CAbsActor::Act(CKungFu *pKungFu)
{
cout<<"演功夫角色"<<endl;
}
void CAbsActor::Act(CFunny *pFunny)
{
cout<<"演諧星角色"<<endl;
}
//CYoung
void CYoung::Act(CKungFu *pKungFu)
{
cout<<"年輕人最喜歡演功夫"<<endl;
}
void CYoung::Act(CFunny *pFunny)
{
cout<<"年輕人愛搞笑"<<endl;
}
//COld
void COld::Act(CKungFu *pKungFu)
{
cout<<"年紀大演功夫很累"<<endl;
}
void COld::Act(CFunny *pFunny)
{
cout<<"年紀大笑點很怪"<<endl;
}
主程式
int main()
{
CAbsActor *pActor = new COld; //定義一個年紀大的演員
CRole *pRole = new CKungFu; //定義一個功夫角色
pRole->Accept(pActor); //演戲
system("pause");
return 0;
}
執行結果:「年紀大演功夫很累」。
缺點:角色子類別不可以太多,設計模式中訪問者模式的注意事項,這裡也要注意。
文章標籤
全站熱搜
留言列表