為了防止被“殺”了祭天昔头,學(xué)點(diǎn)設(shè)計(jì)模式伊群,并總結(jié)下還是有必要的。
一:理解
- 對象包含策略策精,可以根據(jù)不同對象的策略舰始,執(zhí)行不同的操作。
- 就像店家給不同等級(jí)的會(huì)員不同的折扣咽袜,其實(shí)是用不同的策略來為客戶服務(wù)丸卷。
- 策略模式和行為模式類似。
二:例子
你是個(gè)富二代询刹,你有很多朋友谜嫉。
今天,你要在家宴請自己的好朋友凹联。由于朋友太多沐兰,你記不全,但又希望給對方一種很親密的感覺蔽挠,和每個(gè)來賓都打招呼住闯。
于是你叫來了程序員小菜幫你解決這個(gè)打招呼問題。
小菜一來就新建一個(gè)朋友類澳淑,朋友有名字屬性比原。
@Data
public class Friend {
private String name;
public Friend(String name) {
this.name = name;
}
}
為了方便記憶,你讓小菜把把朋友分成四類杠巡,分別是:
- 普通朋友
- 前女友
- 領(lǐng)導(dǎo)
- 老板
小菜分別為每類朋友建立了對應(yīng)的類量窘。
// 普通朋友
public class OrdinaryFriend extends Friend {
public OrdinaryFriend(String name) {
super(name);
}
}
// 前女友
public class ExGirlFriend extends Friend {
public ExGirlFriend(String name) {
super(name);
}
}
// 領(lǐng)導(dǎo)
public class Leader extends Friend {
public Leader(String name) {
super(name);
}
}
// 老板
public class Boss extends Friend {
public Boss(String name) {
super(name);
}
}
今晚,你將用不同的方式和不同類的朋友打招呼氢拥。
小菜幫你設(shè)計(jì)的程序使用if else來判斷來賓的類別蚌铜,并輸出不同的打招呼語句。
看了小菜寫的代碼兄一,你覺得沒什么問題厘线,而且還用到了instanceof這個(gè)你沒見過的運(yùn)算符,覺得小菜還是可以委以重任的出革。
public class Client {
public static void main(String[] args) {
System.out.println("派對開始,開始和來賓寒暄!");
OrdinaryFriend ordinaryFriend = new OrdinaryFriend("Peter");
greet(ordinaryFriend);
ExGirlFriend exGirlFriend = new ExGirlFriend("Mary");
greet(exGirlFriend);
Leader leader = new Leader("Obama");
greet(leader);
Boss boss = new Boss("Jack");
greet(boss);
}
public static void greet(Friend friend) {
if (friend instanceof OrdinaryFriend) {
System.out.println("等著對方打招呼,就是這么高貴,優(yōu)雅!");
} else if (friend instanceof ExGirlFriend) {
System.out.println(friend.getName() + ",你是不是還是放不下我?");
} else if (friend instanceof Leader) {
System.out.println("尊敬的" + friend.getName() + ",您好!");
} else if (friend instanceof Boss) {
System.out.println("尊敬的" + friend.getName() + ",您好!");
}
}
}
派對開始,開始和來賓寒暄!
等著對方打招呼,就是這么高貴,優(yōu)雅!
Mary,你是不是還是放不下我?
尊敬的Obama,您好!
尊敬的Jack,您好!
派對順利地結(jié)束了造壮,你和每位來賓都打了招呼。
然而,隨著你的生意越做越大耳璧,朋友越來越多成箫,地位也越來越高,你需要時(shí)不時(shí)地添加和修改打招呼的方法旨枯。
于是蹬昌,程序員小菜再一次徜徉在修改if else的海洋中。
小菜想攀隔,如果為每個(gè)朋友發(fā)一張身份卡皂贩,掛在胸前,主人看到身份卡就能知道該如何打招呼昆汹。
于是明刷,小菜將打招呼程序進(jìn)行重構(gòu),為每個(gè)朋友發(fā)了一張身份卡满粗,即greet方法辈末。
@Data
public abstract class Friend {
private String name;
public Friend(String name) {
this.name = name;
}
public abstract void greet();
}
Friend基類變成了抽象類,申明了greet方法映皆,具體實(shí)現(xiàn)交給子類挤聘。
// 普通朋友
public class OrdinaryFriend extends Friend {
public OrdinaryFriend(String name) {
super(name);
}
@Override
public void greet() {
System.out.println("等著對方打招呼,就是這么高貴,優(yōu)雅!");
}
}
// 前女友
public class ExGirlFriend extends Friend {
public ExGirlFriend(String name) {
super(name);
}
@Override
public void greet() {
System.out.println(getName() + ",你是不是還是放不下我?");
}
}
// 領(lǐng)導(dǎo)
public class Leader extends Friend {
public Leader(String name) {
super(name);
}
@Override
public void greet() {
System.out.println("尊敬的" + getName() + ",您好!");
}
}
// 老板
public class Boss extends Friend {
public Boss(String name) {
super(name);
}
@Override
public void greet() {
System.out.println("尊敬的" + getName() + ",您好!");
}
}
打招呼時(shí)直接調(diào)用來賓的greet方法即可。
public class Client {
public static void main(String[] args) {
System.out.println("派對開始,開始和來賓寒暄!");
OrdinaryFriend ordinaryFriend = new OrdinaryFriend("Peter");
greet(ordinaryFriend);
ExGirlFriend exGirlFriend = new ExGirlFriend("Mary");
greet(exGirlFriend);
Leader leader = new Leader("Obama");
greet(leader);
Boss boss = new Boss("Jack");
greet(boss);
}
// 直接調(diào)用來賓的greet方法即可
public static void greet(Friend friend) {
friend.greet();
}
}
為了更加精細(xì)地管理自己的朋友圈捅彻,你將自己的朋友圈分組表發(fā)給了小菜组去。
并且你最近學(xué)了英語,希望和某一類朋友(領(lǐng)導(dǎo)/老板等)打招呼的時(shí)候沟饥,使用英語添怔。
小菜發(fā)現(xiàn),雖然你的朋友類別增加到了一百類贤旷,但打招呼的方式只有固定不變的三種广料。
例子中和領(lǐng)導(dǎo)老板打招呼的方式一樣,將打招呼方式修改成英語時(shí)幼驶,需要修改多個(gè)類的greet方法艾杏。
小菜整理了打招呼的策略,整理出三種:
- 裝作沒看到策略盅藻,NoSeeStrategy
- 前女友后悔策略购桑,ExStrategy
- 尊敬策略,RespectStrategy
于是氏淑,小菜采用策略模式勃蜘,提取出一個(gè)策略接口,申明了greet方法假残。
并實(shí)現(xiàn)了三種打招呼策略類缭贡。
// 招呼策略接口
public interface GreetStrategy {
void greet();
}
// 裝作沒看到策略
public class NoSeeStrategy implements GreetStrategy {
@Override
public void greet() {
System.out.println("等著對方打招呼,就是這么高貴,優(yōu)雅!");
}
}
// 前女友后悔策略
public class ExStrategy implements GreetStrategy {
@Override
public void greet() {
System.out.println("你是不是還是放不下我?");
}
}
// 尊敬策略
public class RespectStrategy implements GreetStrategy {
@Override
public void greet() {
System.out.println("尊敬的客人, 您好!");
}
}
修改朋友類炉擅,為朋友加上GreetStrategy屬性。
在普通朋友的構(gòu)造器中阳惹,直接set裝作沒看見策略NoSeeStrategy谍失。
其他幾類類似,不再給出莹汤。
@Data
public class Friend {
private String name;
private GreetStrategy greetStrategy;
public Friend(String name) {
this.name = name;
}
public void greet() {
greetStrategy.greet();
}
}
// 普通朋友類
public class OrdinaryFriend extends Friend {
// 在構(gòu)造器中快鱼,直接setGreetStrategy
public OrdinaryFriend(String name) {
super(name);
setGreetStrategy(new NoSeeStrategy());
}
}
和朋友打招呼時(shí),其實(shí)調(diào)用的是打招呼策略的greet方法纲岭。
用了策略模式之后抹竹,修改和領(lǐng)導(dǎo)/老板打招呼的方法時(shí),不用再同時(shí)修改兩個(gè)類止潮,只需修改RespectStrategy即可柒莉。
public class RespectStrategy implements GreetStrategy {
@Override
public void greet() {
System.out.println("Dear guests, nice to meet you!");
}
}
于是,小菜開心地下班了沽翔。
三:再理解
- 策略模式是對繼承體系的一種再思考。繼承體系中窿凤,使用重寫來表示不同子類的不同策略仅偎,這些策略往往會(huì)重復(fù),提取這些策略雳殊,并新建對應(yīng)的策略類橘沥。
- 策略模式可以避免多次修改,也可以很方便地新增新的策略夯秃。
- 由于朋友子類中的setGreetStrategy是public的座咆,可以臨場修改打招呼的策略,將新的策略set進(jìn)去即可仓洼。
- 策略模式也稱為行為模式介陶,只是分析問題的角度不一樣。
- 行為模式例子:你是個(gè)富二代色建,你有十類女友哺呜,包括嬌小型,淑女型箕戳,熟女型等某残,她們都有papapa的行為,但精通的姿勢不一樣陵吸。由于你的女友實(shí)在太多玻墅,每次papapa的時(shí)候,你需要在腦子里執(zhí)行n多個(gè)if else壮虫,才能決定使用哪種姿勢澳厢。于是你決定讓每個(gè)女友都自帶papapa()方法,在成長的時(shí)候,直接調(diào)用女友的papapa方法即可赏酥。和打招呼一樣喳整,你發(fā)現(xiàn)雖然你有十類女友,但她們papapa的姿勢只有三種裸扶,分別是姿勢A框都,姿勢B和姿勢C,于是你抽象出了三種PapapaBehavior呵晨,女友們都持有PapapaBehavior對象魏保。每次你想開發(fā)新的papapa姿勢時(shí),不用再修改多個(gè)女友類摸屠,只需新增一個(gè)papapa行為類即可谓罗。
- 不同的papapa姿勢對于你而言是策略,而對于女朋友們而言是行為季二。