今天不想寫代碼,給大家帶來一篇設計模式的文章,幫助大家可以把系統組織成容易了解、容易維護、具有彈性的架構。
先來看看策略模式的定義:
策略模式(Strategy Pattern):定義了算法族,分別封裝起來,讓它們之間可相互替換,此模式讓算法的變化獨立於使用算法的客戶。
好了,對於定義,肯定不是一眼就能看明白的,不然這篇文章就收尾了,對於定於大家簡單掃一眼,知道個大概,然后繼續讀下面的文章,讀完以后再來回味,效果嘎嘣脆。大家應該都玩過武俠角色游戲,下面我就以角色游戲為背景,為大家介紹:假設公司需要做一款武俠游戲,我們就是負責游戲的角色模塊,需求是這樣的:每個角色對應一個名字,每類角色對應一種樣子,每個角色擁有一個逃跑、攻擊、防御的技能。
初步的代碼:
- package com.zhy.bean;
- /**
- * 游戲的角色超類
- *
- * @author zhy
- *
- */
- public abstract class Role
- {
- protected String name;
- protected abstract void display();
- protected abstract void run();
- protected abstract void attack();
- protected abstract void defend();
- }
package com.zhy.bean; /** * 游戲的角色超類 * * @author zhy * */ public abstract class Role { protected String name; protected abstract void display(); protected abstract void run(); protected abstract void attack(); protected abstract void defend(); }
- package com.zhy.bean;
- public class RoleA extends Role
- {
- public RoleA(String name)
- {
- this.name = name;
- }
- @Override
- protected void display()
- {
- System.out.println("樣子1");
- }
- @Override
- protected void run()
- {
- System.out.println("金蟬脫殼");
- }
- @Override
- protected void attack()
- {
- System.out.println("降龍十八掌");
- }
- @Override
- protected void defend()
- {
- System.out.println("鐵頭功");
- }
- }
package com.zhy.bean; public class RoleA extends Role { public RoleA(String name) { this.name = name; } @Override protected void display() { System.out.println("樣子1"); } @Override protected void run() { System.out.println("金蟬脫殼"); } @Override protected void attack() { System.out.println("降龍十八掌"); } @Override protected void defend() { System.out.println("鐵頭功"); } }
沒幾分鍾,你寫好了上面的代碼,覺得已經充分發揮了OO的思想,正在竊喜,這時候項目經理說,再添加兩個角色
RoleB(樣子2 ,降龍十八掌,鐵布衫,金蟬脫殼)。
RoleC(樣子1,擁有九陽神功,鐵布衫,煙霧彈)。
於是你覺得沒問題,開始寫代碼,繼續集成Role,寫成下面的代碼:
- package com.zhy.bean;
- public class RoleB extends Role
- {
- public RoleB(String name)
- {
- this.name = name;
- }
- @Override
- protected void display()
- {
- System.out.println("樣子2");
- }
- @Override
- protected void run()
- {
- System.out.println("金蟬脫殼");//從RoleA中拷貝
- }
- @Override
- protected void attack()
- {
- System.out.println("降龍十八掌");//從RoleA中拷貝
- }
- @Override
- protected void defend()
- {
- System.out.println("鐵布衫");
- }
- }
package com.zhy.bean; public class RoleB extends Role { public RoleB(String name) { this.name = name; } @Override protected void display() { System.out.println("樣子2"); } @Override protected void run() { System.out.println("金蟬脫殼");//從RoleA中拷貝 } @Override protected void attack() { System.out.println("降龍十八掌");//從RoleA中拷貝 } @Override protected void defend() { System.out.println("鐵布衫"); } }
- package com.zhy.bean;
- public class RoleC extends Role
- {
- public RoleC(String name)
- {
- this.name = name;
- }
- @Override
- protected void display()
- {
- System.out.println("樣子1");//從RoleA中拷貝
- }
- @Override
- protected void run()
- {
- System.out.println("煙霧彈");
- }
- @Override
- protected void attack()
- {
- System.out.println("九陽神功");
- }
- @Override
- protected void defend()
- {
- System.out.println("鐵布衫");//從B中拷貝
- }
- }
package com.zhy.bean; public class RoleC extends Role { public RoleC(String name) { this.name = name; } @Override protected void display() { System.out.println("樣子1");//從RoleA中拷貝 } @Override protected void run() { System.out.println("煙霧彈"); } @Override protected void attack() { System.out.println("九陽神功"); } @Override protected void defend() { System.out.println("鐵布衫");//從B中拷貝 } }
寫完之后,你自己似乎沒有當初那么自信了,你發現代碼中已經存在相當多重復的代碼,需要考慮重新設計架構了。於是你想,要不把每個技能都寫成接口,有什么技能的角色實現什么接口,簡單一想,覺得這想法高大尚啊,但是實現起來會發現,接口並不能實現代碼的復用,每個實現接口的類,還是必須寫自己寫實現。於是,we need change ! 遵循設計的原則,找出應用中可能需要變化的部分,把它們獨立出來,不要和那些不需要變化的代碼混在一起。我們發現,對於每個角色的display,attack,defend,run都是有可能變化的,於是我們必須把這寫獨立出來。再根據另一個設計原則:針對接口(超類型)編程,而不是針對實現編程,於是我們把代碼改造成這樣:
- package com.zhy.bean;
- public interface IAttackBehavior
- {
- void attack();
- }
package com.zhy.bean; public interface IAttackBehavior { void attack(); }
- package com.zhy.bean;
- public interface IDefendBehavior
- {
- void defend();
- }
package com.zhy.bean; public interface IDefendBehavior { void defend(); }
- package com.zhy.bean;
- public interface IDisplayBehavior
- {
- void display();
- }
package com.zhy.bean; public interface IDisplayBehavior { void display(); }
- package com.zhy.bean;
- public class AttackJY implements IAttackBehavior
- {
- @Override
- public void attack()
- {
- System.out.println("九陽神功!");
- }
- }
package com.zhy.bean; public class AttackJY implements IAttackBehavior { @Override public void attack() { System.out.println("九陽神功!"); } }
- package com.zhy.bean;
- public class DefendTBS implements IDefendBehavior
- {
- @Override
- public void defend()
- {
- System.out.println("鐵布衫");
- }
- }
package com.zhy.bean; public class DefendTBS implements IDefendBehavior { @Override public void defend() { System.out.println("鐵布衫"); } }
- package com.zhy.bean;
- public class RunJCTQ implements IRunBehavior
- {
- @Override
- public void run()
- {
- System.out.println("金蟬脫殼");
- }
- }
package com.zhy.bean; public class RunJCTQ implements IRunBehavior { @Override public void run() { System.out.println("金蟬脫殼"); } }
這時候需要對Role的代碼做出改變:
- package com.zhy.bean;
- /**
- * 游戲的角色超類
- *
- * @author zhy
- *
- */
- public abstract class Role
- {
- protected String name;
- protected IDefendBehavior defendBehavior;
- protected IDisplayBehavior displayBehavior;
- protected IRunBehavior runBehavior;
- protected IAttackBehavior attackBehavior;
- public Role setDefendBehavior(IDefendBehavior defendBehavior)
- {
- this.defendBehavior = defendBehavior;
- return this;
- }
- public Role setDisplayBehavior(IDisplayBehavior displayBehavior)
- {
- this.displayBehavior = displayBehavior;
- return this;
- }
- public Role setRunBehavior(IRunBehavior runBehavior)
- {
- this.runBehavior = runBehavior;
- return this;
- }
- public Role setAttackBehavior(IAttackBehavior attackBehavior)
- {
- this.attackBehavior = attackBehavior;
- return this;
- }
- protected void display()
- {
- displayBehavior.display();
- }
- protected void run()
- {
- runBehavior.run();
- }
- protected void attack()
- {
- attackBehavior.attack();
- }
- protected void defend()
- {
- defendBehavior.defend();
- }
- }
package com.zhy.bean; /** * 游戲的角色超類 * * @author zhy * */ public abstract class Role { protected String name; protected IDefendBehavior defendBehavior; protected IDisplayBehavior displayBehavior; protected IRunBehavior runBehavior; protected IAttackBehavior attackBehavior; public Role setDefendBehavior(IDefendBehavior defendBehavior) { this.defendBehavior = defendBehavior; return this; } public Role setDisplayBehavior(IDisplayBehavior displayBehavior) { this.displayBehavior = displayBehavior; return this; } public Role setRunBehavior(IRunBehavior runBehavior) { this.runBehavior = runBehavior; return this; } public Role setAttackBehavior(IAttackBehavior attackBehavior) { this.attackBehavior = attackBehavior; return this; } protected void display() { displayBehavior.display(); } protected void run() { runBehavior.run(); } protected void attack() { attackBehavior.attack(); } protected void defend() { defendBehavior.defend(); } }
每個角色現在只需要一個name了:
- package com.zhy.bean;
- public class RoleA extends Role
- {
- public RoleA(String name)
- {
- this.name = name;
- }
- }
package com.zhy.bean; public class RoleA extends Role { public RoleA(String name) { this.name = name; } }
現在我們需要一個金蟬脫殼,降龍十八掌!,鐵布衫,樣子1的角色A只需要這樣:
- package com.zhy.bean;
- public class Test
- {
- public static void main(String[] args)
- {
- Role roleA = new RoleA("A");
- roleA.setAttackBehavior(new AttackXL())//
- .setDefendBehavior(new DefendTBS())//
- .setDisplayBehavior(new DisplayA())//
- .setRunBehavior(new RunJCTQ());
- System.out.println(roleA.name + ":");
- roleA.run();
- roleA.attack();
- roleA.defend();
- roleA.display();
- }
- }
package com.zhy.bean; public class Test { public static void main(String[] args) { Role roleA = new RoleA("A"); roleA.setAttackBehavior(new AttackXL())// .setDefendBehavior(new DefendTBS())// .setDisplayBehavior(new DisplayA())// .setRunBehavior(new RunJCTQ()); System.out.println(roleA.name + ":"); roleA.run(); roleA.attack(); roleA.defend(); roleA.display(); } }
經過我們的修改,現在所有的技能的實現做到了100%的復用,並且隨便項目經理需要什么樣的角色,對於我們來說只需要動態設置一下技能和展示方式,是不是很完美。恭喜你,現在你已經學會了策略模式,現在我們回到定義,定義上的算法族:其實就是上述例子的技能;定義上的客戶:其實就是RoleA,RoleB...;我們已經定義了一個算法族(各種技能),且根據需求可以進行相互替換,算法(各種技能)的實現獨立於客戶(角色)。現在是不是很好理解策略模式的定義了。
附上一張UML圖,方便大家理解:
最后總結一下OO的原則:
1、封裝變化(把可能變化的代碼封裝起來)
2、多用組合,少用繼承(我們使用組合的方式,為客戶設置了算法)
3、針對接口編程,不針對實現(對於Role類的設計完全的針對角色,和技能的實現沒有關系)