摘要:引言要分析设计模式中的策略模式,我们可以以希伯来圣经中的一个故事为例。策略模式原理及益处这个策略依然有一个父类相当于一个模板,所有的人类子类都继承这个父类根据这个模板来创建。
引言
要分析设计模式中的“策略模式”,我们可以以《希伯来圣经》中的一个故事为例。
《希伯来圣经》中有这样一个故事,说的是人类产生不同语言的起源。在这个故事中,一群只说一种语言的人在“大洪水”之后从东方来到了示拿地区,并决定在这修建一座城市和一座“能够通天的”高塔;上帝见此情形就把他们的语言打乱,让他们再也不能明白对方的意思,并把他们分散到了世界各地。
这里我们可以将God视作一个程序员。
在他的设计中,所有的人类(Human),虽然有很多个个体,但一开始都是一样的,说的是一样的语言。
所以我们可以将Human类作为父类,然后所有的人类个体对象都继承这个Human父类。父类中有一个speak()方法,所有继承Human类的子类都将继承这个方法,于是都拥有了用语言交流的能力。
//Human父类 public class Human { public void speak(){ System.out.println("只要是人类的子类都speak the same language"); } }
可以有很多的人类种类继承这个Human父类,比如来自东方的的人:
public class PeopleFromEast extends { //PeopleFromEast继承了Human, //所以也就继承了Human父类中的speak()方法 //所以PeopleFromEast类中甚至都不需要写任何方法 }
在demo测试中,我们可以看到,PeopleFromEast类的对象,可以调用从父类继承来的speak()方法:
public class RunDemo { public static void main (String[] args){ //创建一个PeopleFromEast对象 PeopleFromEast peopleFromEast = new PeopleFromEast(); //让这个对象调用从父类继承来的方法speak() peopleFromEast.speak(); } }
根据God最初的设想,这样的设计是没有问题的。
“土方法”的缺陷可是后来由于语言一致,人类同心协力修建巴比塔,(程序猿)God感到受到了威胁。于是决定做出改变:让来自不同地方的人speak不同的language——比如PeopleFromEast说EastLanguage,PeopleFromWest说WestLanguage,等等。
God要实现这样的改变,最直观的方法自然是让每个继承Human父类的人类子类重写父类的speak()方法。
//新的PeopleFromEast类 //这一次PeopleFromEast重写了speak()方法 public class PeopleFromEast extends Human { @Override public void speak() { System.out.println("PeopleFromEast从今以后只能speak EastLanguage"); } }
demo的运行结果:
如果人类的子类种类不多,那么(程序猿God)还可以每次都重写Human子类的speak()方法。可是如果人类的子类有很多种呢?又或者不止speak()方法有这种情况呢?比如,也许God以后希望让每种人类子类的行走方式都不一样。那是不是应该在Human父类中加入一个walk()方法,然后让每个子类都重写呢?
也就是说,如果人类子类的“规格”常常改变,每当有新的人类子类出现,(程序猿)God都要被迫检查并可能需要覆盖speak()和walk(),这绝对是God所不愿意看见的。
策略模式原理及益处这个策略依然有一个Human父类(相当于一个模板),所有的人类子类都继承这个父类(根据这个模板来创建)。
所不同的是,这次God决定在每个人类的子类中都附上自己的一份意识。让这份意识来控制这个子类应该说的语言种类。为了方便叙述,我们可以将God的这一意识称为LanguageController。
然后,God为人类的子类可以说的Language种类提供了一个选择范围。
比如,中国人(ChineseMan--因为Chinese既可以表示“中文”又可以表示“中国人”,为了区分,我们称“中国人”为"ChineseMan")说中文(Chinese),美国人(American)就说英文(English)。
这样一来,在每个人类子类创建时,God附在其上的意识LanguageController将发挥作用,然后按照God的意愿,从language的可选范围中选择一种语言来指定给该人类子类。
这一策略在程序设计中可以这样实现:
创建一个Human父类:
public class Human { //LanguageController是接口类型 //languageController作为Human类的field, //代表God将自己的意识附在人类父类之上, //也就代表God的意识将附在所有的人类个体之上 LanguageController languageController ; //根据God的设计,人类的模板中只需要作出规定:人会说某种语言 //而不需要作出具体的安排 public void performSpeaking (){ //人说话的时候,还得上帝的意识起作用, //决定这个“具体的人”该说何种语言 languageController.speak(); } }
创建LanguageController接口:
//创造God的意识,也就是LanguageController: public interface LanguageController { //接口中只定义了一个speak()方法 public void speak(); }
现在God要创造中国人和美国人:
ChineseMan类:
public class ChineseMan extends Human { //中国人对象的构造器 ChineseMan() { //构造ChineseMan对象时,God的意识发挥作用 //languageController是从Human父类继承来的 //根据God的安排,要创建ChineseMan对象,就应该告诉languageController现在要创造的这个对象说中文 languageController = new speakChinese(); //在这里,由于多态的缘故,表现为具体子类--也就是speakChinese对象 skinColorController = new ColorIsLikeAsian(); } }
American类:
public class American extends Human { //American的构造器 public American (){ languageController = new SpeakEnglish(); } }
那么这个speakChinese类和speakEnglish类有什么玄机呢?
speakChinese类:
//speakChinese类实现了LanguageController接口 public class speakChinese implements LanguageController{ //实现LanguageController接口中规定的speak()方法 @Override public void speak() { System.out.println("我说中文!"); } }
speakChinese类可能不太好理解,因为speak Chinese(说中文)更多算是一种行为(action),这里却定义为类。其实只需要换一种思维,把speakChinese类视作一种标签,把这个标签赋给God的意识(languageContronller),也就实现了根据不同的human子类来确定不同的语言。
speakEnglish类:
//SpeakEnglish类实现了LanguageController接口 public class SpeakEnglish implements LanguageController { @Override public void speak() { System.out.println("I speak English!"); } }
下面运行一个demo--StrategyModeDemo.java:
public class StrategyModeDemo { public static void main(String[] args){ //新建一个ChineseMan对象 Human chineseMan = new ChineseMan(); //ChineseMan说的语言: chineseMan.performSpeaking(); //American对象: Human american = new American(); //American说的语言: american.performSpeaking(); } }
StrategyModeDemo.java运行结果:
执行逻辑图示而整个执行流程的逻辑则如图所示:
更上一层楼当然,以上所有的Human子类在被创建时,他们说什么话就已经注定了。
这是因为他们的God的意识起作用的环节在他们的构造器中。
那么God有没有办法让已经被造出来的ChineseMan对象改说English呢?
答案是肯定的!
我们只需要在Human.java中加入一个修改语言的方法即可:
public class Human { LanguageController languageController ; SkinColorController skinColorController; //控制Human的子类说的语言,比如中国人说中文 public void performSpeaking (){ languageController.speak(); } //随时改变能说的语言 public void setLanguage (LanguageController languageController){ languageController.speak(); } }
再次运行StrategyModeDemo.java:
public class StrategyModeDemo { public static void main(String[] args){ //新建一个ChineseMan对象 Human chineseMan = new ChineseMan(); //ChineseMan说的语言: chineseMan.performSpeaking(); System.out.println("God决定让ChineseMan也说英文"); chineseMan.setLanguage(new SpeakEnglish()); } }
个人浅见,如有不足,欢迎批评指正:)
文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。
转载请注明本文地址:https://www.ucloud.cn/yun/74616.html
摘要:可以使用其他模式来修正这个缺陷,如工厂方法模式代理模式或享元模式。我们的策略模式只是实现了策略的管理,但是没有严格地定义适当的场景使用适当的策略,在实际项目中,一般通过工厂方法模式来实现策略类的声明。源码地址参考文献设计模式之禅 定义 Define a family of algorithms,encapsulate each one,and make them interchange...
摘要:一定义定义维基百科策略模式作爲一種軟件設計模式,指對象有某個行爲,但是在不同的場景中,該行爲有不同的實現算法。二策略模式图我们看看策略模式是有怎样设计结构的。如中创建线程池,线程池任务满时,对提交的任务做处理就使用了策略模式。以前完整的看过《大话设计模式》,虽然完整看过,也做过笔记,但现在依然很多已经很模糊。这段时间趁着离职,有时间,打算重新过一遍,该篇将介绍策略模式。一、定义定义(维基百科...
摘要:孙膑心里一万个草泥马在奔腾,差点没噎死自己滚一边去,我们这盘跟他赛马开始,策略模式上场。在设计模式之禅中的提出通过策略枚举和反射机制对策略模式进行改良,膜拜了但是要添加或淘汰策略,还是得去对枚举进行修改,也不符合开闭原则。 今天给大家说说田忌赛马的故事。如有雷同,纯属巧合!话说在战国时期,群雄割据,硝烟四起,茶余饭后还是少不了娱乐活动的,其中赛马是最火爆的。一天,孙膑看到田忌像个死鸡似...
阅读 2663·2023-04-25 20:19
阅读 1906·2021-11-24 09:38
阅读 1609·2021-11-16 11:44
阅读 4233·2021-09-02 15:40
阅读 1294·2019-08-30 15:55
阅读 1998·2019-08-30 15:52
阅读 3733·2019-08-29 17:20
阅读 2167·2019-08-29 13:48