- netbeans自动生成的web.xml问题
- Java执行shell命令的问题求助
- JSP和IIS之间的最佳解决方案
- Spring中的autowire属性
- 在Hibernate下如何truncate一个表
- 怎么让 Java 编译器使用即时编译?
- 怎样读取当前文件指针下一个位置的字符等
- 批处理设ip和dns
- Hibernate+ORACLE
- java中为什么静态函数局部变量没有意义?
- NetStore源代码+功能演示
- java如何运行linux中的shell命令!
- 数据库方言和显示SQL....HIBERNATE....不明白...
- java socket 长连接问题
- javax.servlet.*;找不到
- Servlet字符编码问题的疑问[Linux]
- java 掉进程
- NoClassDefFoundError: org/hibernate/Session 急啊..
- suse 下如何 编译 java
- (求):Thinking in Java 3的习题答案
我眼中的策略模式
前一段时间在朋友的极力推荐下,有幸拜读了head.first 的大作《设计模式》,阅读了几章之后猛然发现,原来技术文章也可以写的如此通俗,优雅。遂想将个人的一些读后感和对书中设计模式的理解整理成文,与众程序员朋友分享。同时,也希望您能慷慨的发表自己的看法与理解,帮助新晋的程序员朋友在软件开发之路上走的更加从容。如果您正好看过此书,请一定不吝赐教。欢迎大家拍砖!
下面是我对书中策略模式的讲解的分析:
场景:一款模拟鸭子的游戏,游戏中出现各种鸭子,一边戏水,一边呱呱叫
描述:有一个鸭子的抽象类,各种鸭子继承此类
鸭子种类:红头鸭,绿头鸭,木头假鸭,橡皮鸭
抽象类的方法:quack(),swim(),abstract display()
补充:抽象类中已对quack和swim进行了实现。鸭子正常叫为呱呱叫,红头与绿头鸭呱呱叫,木头鸭不会叫,橡皮鸭会吱吱叫
此设计优点:子类可复用quack(),swim()方法
此设计缺点:个别种类的鸭子需要覆盖父类的quack方法满足自己的需求(例如木头鸭不会叫)
Java代码
| 1.public abstract class Duck{ 2. public void quack(){ 3. System.out.println("呱呱叫"); 4. } 5. 6. public void swim(){ 7. System.out.println("戏水"); 8. } 9. 10. public abstract void display(); 11.} public abstract class Duck{ public void quack(){ System.out.println("呱呱叫"); } public void swim(){ System.out.println("戏水"); } public abstract void display(); } |
需求:需要某些鸭子能够飞行
方案一:在超类中增加fly()方法并对其实现
缺点:所有的鸭子都拥有了fly()的功能,哪怕本身不能fly(),凡是增加新的鸭子类都需要对fly()方法进行检测,如不需要则必须覆盖
Java代码
| 1.public abstract class Duck{ 2. public void quack(){ 3. System.out.println("呱呱叫"); 4. } 5. 6. public void swim(){ 7. System.out.println("戏水"); 8. } 9. 10. public void fly(){ 11. System.out.println("飞行"); 12. } 13. 14. public abstract void display(); 15.} public abstract class Duck{ public void quack(){ System.out.println("呱呱叫"); } public void swim(){ System.out.println("戏水"); } public void fly(){ System.out.println("飞行"); } public abstract void display(); } |
方案二:将fly()方法抽出写入接口,需要的自行实现该接口
缺点:无法复用,重复代码增多
Java代码
| 1.public interface Flyable{ 2. public void fly(); 3.} public interface Flyable{ public void fly(); } |
症结:鸭子的某些行为在子类中会不断的变化,让所有子类都拥有这类的行为是不恰当的
设计原则:(封装变化)找出应用中可能需要变化之处,把它们独立出来,和不需要改变的分开,以便它们可以独立的修改和扩展而不影响其他部分
解答:将fly,quack方法抽出为两组独立的类型,并根据需要进行不同的实现。例如,quack类型组可以包含,安静,呱呱叫,吱吱叫
Java代码
| 1.public interface Quack{ 2. public void quack(); 3.} 4. 5.public interface Flyable{ 6. public void fly(); 7.} 8. 9.public class FlyWithWing implements Flyable{ 10. public void fly(){ 11. System.out.println("用翅膀飞行"); 12. } 13.} 14. 15.public class ZhiZhiQuack implements Quack{ 16. public void quack(){ 17. System.out.println("吱吱叫"); 18. } 19.} 20. 21.public class GuaGuaQuack implements Quack{ 22. public void quack(){ 23. System.out.println("呱呱叫"); 24. } 25.} public interface Quack{ public void quack(); } public interface Flyable{ public void fly(); } public class FlyWithWing implements Flyable{ public void fly(){ System.out.println("用翅膀飞行"); } } public class ZhiZhiQuack implements Quack{ public void quack(){ System.out.println("吱吱叫"); } } public class GuaGuaQuack implements Quack{ public void quack(){ System.out.println("呱呱叫"); } } |
补充:由于一开始鸭子行为设计的没有弹性才出现了以上的情况,所以应该采用一种弹性的方案。可以根据需要动态改变鸭子的行为
设计原则:(鸭子类不在拥有具体的行为实现方法,只拥有行为的引用接口)针对接口编程,而不是针对实现编程
解答:鸭子的行为放在分开的类中,让该类提供某行为接口的实现
设计原则:多用组合,少用继承(鸭子的行为不再是继承而来,而是组合而来)
设计模式:策略模式,定义了算法族(鸭子的行为类型组),分别封装起来,让他们之间可以相互替换,此模式让算法的变化(鸭子的行为)独立于使用算法的客户(鸭子)
Java代码
| 1.public abstract class Duck{ 2. private Quack quack; 3. private Flyable fly; 4. 5. public void executeQuack(){ 6. quack.quack(); 7. } 8. 9. public void executeFly(){ 10. fly.fly(); 11. } 12. 13. public void setQuack(Quack q){ 14. this.quack=q; 15. } 16. 17. public void setFly(Flyable f){ 18. this.fly=f; 19. } 20. 21. public void swim(){ 22. System.out.println("戏水"); 23. } 24. 25. public abstract void display(); 26.} public abstract class Duck{ private Quack quack; private Flyable fly; public void executeQuack(){ quack.quack(); } public void executeFly(){ fly.fly(); } public void setQuack(Quack q){ this.quack=q; } public void setFly(Flyable f){ this.fly=f; } public void swim(){ System.out.println("戏水"); } public abstract void display(); } |
子类在构造时设定具体的行为即可,并且在运行时也可动态改变。
下面是我对此模式中所使用的一些软件设计原则的看法与感悟:
封装变化:
1.为每种行为的变化定义接口
2.将每种具体的行为封装为类并实现该种行为的接口
解释:本例中的变化的类型是鸭子的行为,包含fly,quack两组。分别对其定义接口,再根据具体的需求予以实现。例如quack接口包含(呱呱叫,吱吱叫,无声)三种具体的实现
针对接口编程:
1.将具体实现委托给接口
2.问题域类只负责接口级别的逻辑控制
3.问题域类的责任依赖于持有的抽象接口而不是具体实现
解释:鸭子类只持有行为的接口,本身不负责实现。对鸭子类进行了细粒度的抽象,将其具体的行为予以抽离,该问题域类(鸭子)的责任只依赖于内部所持有的接口
多用组合,少用继承:
1.通过组合的方式构建类的行为,而不是继承。可以使类更加灵活,在运行期可动态改变行为
以上便是我的理解,如有不对或者疑惑之处欢迎指出!文中只写出主要的代码,其他代码均已省略,若有需要的朋友可自行参阅该书,亦可发站内信向我索取!
此篇文章发表于:百家学院 (http://www.9php.com),复制请保留此行.
·上一篇:一个进程每次启动其线程ID不变? · 下一篇:MQ在LINUX下安装配置

