1.Strategy Pattern(策略模式)

策略模式(Strategy Pattern):

  我的理解,将代码中每个变化之处抽出,提炼成一个一个的接口或者抽象类,让这些变化实现接口或继承抽象类成为具体的变化类。再利用多态的功能,可将变化之处用接口或抽象类的对象代替,再用其子类为对象赋值,这样就可以将对象随时更换成具体的变化类。

  枯燥的文字描述总是没有实际的例子浅显易懂。

举例:(我是基于notepad++和cmd命令编译运行的JAVA代码

  现在有个鸭子俱乐部,里面有各式各样的鸭子(只有想不到,没有做不到的鸭子)。

  我们来一步一步实现这个鸭子类:

  1.定义一个抽象鸭子类(Duck):

 1 public abstract class Duck{//抽象鸭子类
 2     public void fly(){//行为:飞行
 3         System.out.println("I'm flying!");
 4     }
 5     public void quack(){//行为:呱呱叫
 6         System.out.println("Gua Gua!");
 7     }
 8     public void swim(){//行为:游泳
 9         System.out.println("I'm swimming!");
10     }
11 }
Duck

  2.实现一个正常的鸭子类(GreenDuck):

1 public class GreenDuck extends Duck{//GreenDuck直接继承Duck,什么都不做
2     
3     public GreenDuck(){
4     }
5 }
GreenDuck

  3.测试类(DuckTest):

1 public class DuckTest{//测试类
2     public static void main(String args[]){
3         GreenDuck greenDuck = new GreenDuck();//实例化一只GreenDuck
4         greenDuck.fly();
5         greenDuck.quack();
6         greenDuck.swim();
7     }
8 }
DuckTest

  编译运行+结果:

  大功告成!我们去庆祝一下。

  正在庆祝,鸭子俱乐部来电话说,我们不仅只要一只GreenDuck,还要RedDuck...不管什么颜色的鸭子都要。你一口应承下来,没问题只是多写几个继承的类而已。

  鸭子俱乐部继续说道,我们还要不会飞,不会叫的橡皮鸭,所有颜色的橡皮鸭来一套。你很心虚的答应了,可能今晚要加班加点了,让各种颜色的橡皮鸭继承Duck但是要覆盖其中的fly和quack行为。

  鸭子俱乐部没完没了的继续说道,我们还要各种颜色的鸭鸣器,它们只会叫不会飞。现在你心里一定恨死各种颜色这个单词了。

  鸭子俱乐部嘴停不下来说各种颜色的...

  .......

  第二天,哭晕在厕所中。

   现在,来看看到底是什么问题导致我们要不停的重复写大量的代码:各种颜色

  没错就是这个单词让我们不停地去写各种各样的鸭子实现类(都继承自Duck抽象类),并且有的鸭子不会飞,有的会飞不会叫...

  现在有没有感觉到继承带来的恐惧感?我们可以让所有的同类鸭子都继承自Duck抽象类,但是每种鸭子都有自己独特的行为,导致我们要不停地去覆盖Duck抽象类中的行为。

  问题找到了。就是继承自抽象类的行为不符合每种鸭子独特的行为导致我们不停地去手动改写或添加行为。我们写这么多的重复代码,没有将代码复用,比如,有的鸭子会飞,有的鸭子会叫,有的鸭子会游泳,有的鸭子不会叫...这么多的行为都写在鸭子实现类中,导致代码冗余,没有将它们复用。

下面让我们的救星:策略模式(Strategy Pattern)登场:

  1.首先,fly()和quack()两个方法是一直在变化的,所以我们将这两个变化之处从Duck抽象类中提炼出来变成FlyBehavior接口和QuackBehavior接口,并在Duck抽象类中定义flyBehavior和quackBehavior两个对象。

 1 public abstract class Duck{//抽象鸭子类
 2 
 3     /*增加两个接口对象*/
 4     FlyBehavior flyBehavior;//飞行类对象
 5     QuackBehavior quackBehavior;//呱呱叫类对象
 6     
 7     public Duck(){
 8     }
 9     
10     //去除下面两个方法
11     /*public void fly(){//行为:飞行
12         System.out.println("I'm flying!");
13     }
14     public void quack(){//行为:呱呱叫
15         System.out.println("Gua Gua!");
16     }*/
17     
18     /*增加下面两个方法,这就是将Duck类的行为委托给两个接口对象实现*/
19     public void performFly(){//将fly()委托给flyBehavior对象实现
20         flyBehavior.fly();
21     }
22     public void performQuack(){//将quack()委托给quackBehavior对象实现
23         quackBehavior.quack();
24     }
25     
26     
27     public void swim(){//行为:游泳
28         System.out.println("I'm swimming!");
29     }
30 }
Duck
1 public interface FlyBehavior{//从Duck抽象类中抽出的fly()方法变成了FlyBehavior接口
2     public void fly();
3 }
FlyBehavior
1 public interface QuackBehavior{//从Duck抽象类中抽出的quack()方法变成了QuackBehavior接口
2     public void quack();
3 }
QuackBehavior

  其次,将变化具体类分别继承FlyBehavior和QuackBehavior两个接口:

  两个飞行具体变化类:

1 public class FlyWithWings implements FlyBehavior{
2     public void fly(){
3         System.out.println("I'm flying!");
4     }
5 }
FlyWithWings
1 public class FlyNoWay implements FlyBehavior{
2     public void fly(){
3         System.out.println("I can't fly!");
4     }
5 }
FlyNoWay

  两个呱呱叫具体变化类:

1 public class Quack implements QuackBehavior{
2     public void quack(){
3         System.out.println("Quack quack!");
4     }
5 }
Quack
1 public class MuteQuack implements QuackBehavior{
2     public void quack(){
3         System.out.println("<< Silence >>");
4     }
5 }
MuteQuack

  最后,实现一个具体类和测试类:

 1 public class GreenDuck extends Duck{//GreenDuck直接继承Duck
 2     
 3     public GreenDuck(){
 4         flyBehavior = new FlyWithWings();
 5         quackBehavior = new Quack();
 6     }
 7     
 8     /*增加一个展示自己是什么鸭子的方法*/
 9     public void display(){
10         System.out.println("I'm GreenDuck!");
11     }
12 }
GreenDuck
1 public class DuckTest{//测试类
2     public static void main(String args[]){
3         GreenDuck greenDuck = new GreenDuck();//实例化一只GreenDuck
4         greenDuck.performFly();
5         greenDuck.performQuack();
6         greenDuck.swim();
7         greenDuck.display();
8     }
9 }
DuckTest

编译运行,结果:

上面的结果,我们可以随时随地的实现不同的具体的鸭子类了,只要在具体的鸭子类中为flyBehavior和quackBehavior实现不同的变化类就好。

  2.动态的实现具体变化类的改变:

  在Duck类中添加两个新方法(setFlyBehavior(Flybehavior fb)和 setQuackBehavior(QuackBehavior qb) ):

 1 public abstract class Duck{//抽象鸭子类
 2 
 3     /*增加两个接口对象*/
 4     FlyBehavior flyBehavior;//飞行类对象
 5     QuackBehavior quackBehavior;//呱呱叫类对象
 6     
 7     public Duck(){
 8     }
 9     
10     //去除下面两个方法
11     /*public void fly(){//行为:飞行
12         System.out.println("I'm flying!");
13     }
14     public void quack(){//行为:呱呱叫
15         System.out.println("Gua Gua!");
16     }*/
17     
18     /*增加下面两个方法,这就是将Duck类的行为委托给两个接口对象实现*/
19     public void performFly(){//将fly()委托给flyBehavior对象实现
20         flyBehavior.fly();
21     }
22     public void performQuack(){//将quack()委托给quackBehavior对象实现
23         quackBehavior.quack();
24     }
25     
26     /*添加两个新方法,可以动态的改变具体变化类*/
27     public void setFlyBehavior(FlyBehavior fb){
28         flyBehavior = fb;
29     }
30     public void setQuackBehavior(QuackBehavior qb){
31         quackBehaior = qb;
32     }
33     
34     
35     public void swim(){//行为:游泳
36         System.out.println("I'm swimming!");
37     }
38 }
Duck

  改造测试类:

 1 public class DuckTest{//测试类
 2     public static void main(String args[]){
 3         GreenDuck greenDuck = new GreenDuck();//实例化一只GreenDuck
 4         greenDuck.performFly();//一开始GreenDuck会飞
 5         greenDuck.performQuack();//一开始GreenDuck会叫
 6         
 7         /*动态改变greenDuck的行为*/
 8         greenDuck.setFlyBehavior(new FlyNoWay());
 9         greenDuck.setQuackBehavior(new MuteQuack());
10         
11         greenDuck.performFly();//现在不会飞了
12         greenDuck.performQuack();//现在不会叫了
13     }
14 }
DuckTest

编译运行,结果:

代码下载网址:

https://github.com/lanshanxiao/Head-First-Design-Pattern/tree/master/1.%E7%AD%96%E7%95%A5%E6%A8%A1%E5%BC%8F(StrategyPattern)%E8%AE%B2%E8%A7%A3%E4%BB%A3%E7%A0%81/%E7%AE%80%E5%8D%95%E5%AE%9E%E7%8E%B0

 

提炼一下思想:

1.封装

2.“有一个” 比 “是一个” 好(has-a 比 is-a好)

3.多用组合少用继承

4.封装变化

5.针对接口编程,不针对实现编程

转载于:https://www.cnblogs.com/lanshanxiao/p/7878631.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/368575.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Spring MVC + Hibernate + Maven:CRUD操作示例

在本文中&#xff0c;我想研究一个Spring MVC Hibernate Maven用法的示例。 这套技术暗含领域领域的基础知识。 因此&#xff0c;我将尝试详细解释所有重要时刻。 其他没有主题的内容将提供指向更多详细信息源的链接。 在文章的结尾&#xff0c;我将发布GitHub的链接。 目标…

画出的点做交互_设计之下交互设计原型设计之概念设计

目录//交互设计//「设计之下」---交互设计&#xff1a;交互设计师是做什么的&#xff1f;上线的产品中那一块是交互设计师的产物呢&#xff1f;项目启动1.1「设计之下」---交互设计&#xff1a;项目启动之从想法到项目&#xff0c;什么是项目&#xff1f;1.2「设计之下」---交互…

Java集合之TreeMap源码解析上篇

上期回顾 上期我从树型结构谈到了红黑树的概念以及自平衡的各种变化&#xff08;指路上期←戳&#xff09;&#xff0c;本期我将会对TreeMap结合红黑树理论进行解读。 首先&#xff0c;我们先来回忆一下红黑树的5条基本规则。 1.结点是红色或者黑色&#xff0c; 2.根结点为黑色…

CSS3 Transform、Transition和Animation属性总结

CSS3的三个与变形和动画啊相关的属性&#xff1a; Transform 浏览器支持情况&#xff1a; Internet Explorer 10、Firefox、Opera 支持 transform 属性。 Internet Explorer 9 支持替代的 -ms-transform 属性&#xff08;仅适用于 2D 转换&#xff09;。 Safari 和 Chrome…

综合云平台 - 前言 - 00

因为学习了 RHCA 云方向, 目前已经学了: CL210 OpenStack 私有云技术 CL220 CFME 混合云管理平台 RH236 GlusterFS 分布式存储 RH413 Hardening 安全 RH442 Performance Tuning 调优 RH318 Red Hat Enhanced Virtualization 虚拟化(传统虚拟机) DO280 OpenS…

15秋计算机基础作业3,东师15秋《计算机应用基础》在线作业3介绍.doc

计算机应用基础15秋在线作业3一、单选题(共?25?道试题&#xff0c;共?62.5?分。)V1.??国标码与机内码之间区别是A. 在机器内所占存储单元不同B. 机内码是ASCII码&#xff0c;国标码为非ASCII码C. 国标码是个每个字节最高位为1&#xff0c;机内码每个字节最高位为1D. 机内…

在Java中使用DOM,SAX和StAX解析器解析XML

我碰巧通读了有关Java中的XML解析和构建API的章节。 我试用了样本XML上的其他解析器。 然后&#xff0c;我想在我的博客上分享它&#xff0c;这样我就可以参考该代码以及任何阅读此书的参考。 在本文中&#xff0c;我将在不同的解析器中解析相同的XML&#xff0c;以执行将XML内…

仪器和软件通讯测试软件,软件定义的仪器-测试测量-与非网

如同每个孩子所拥有的第一套LEGO玩具改变了他们对世界的认识一样&#xff0c;26年前&#xff0c;美国国家仪器通过NI LabVIEW系统设计软件&#xff0c;重新改变了人们对仪器的认知。今年&#xff0c;NI将再次重演历史&#xff0c;发布一款新型仪器&#xff0c;帮助测试工程师摆…

埃森哲杯第十六届上海大学程序设计联赛春季赛暨上海高校金马五校赛 C序列变换...

链接&#xff1a;https://www.nowcoder.com/acm/contest/91/C来源&#xff1a;牛客网没有账号的同学这样注册&#xff0c;支持博主 题目描述 给定两个长度为n的序列&#xff0c;ai, bi(1<i<n), 通过3种魔法使得序列a变换为序列b&#xff0c;也就是aibi(1<i<n). 魔…

ubuntu安装gnome桌面

1. apt install gnome-shell2. apt install ubuntu-gnome-desktop3. apt install unity-tweak-tool4. apt install gnome-tweak-tool转载于:https://www.cnblogs.com/regit/p/7978365.html

Spring MVC,Ajax和JSON第1部分–设置场景

我一直在考虑在Spring&#xff0c;Ajax和JSON上写博客&#xff0c;但是我从来没有做过。 这主要是因为它非常复杂&#xff0c;并且所需的技术一直处于变化状态。 当我决定撰写此博客时&#xff0c;我在Internet上有一个侦察员&#xff0c;如果您查看诸如Stack Overflow之类的地…

oracle 运营维护_Oracle数据库日常运维常用脚本

大中小Oracle数据库日常运维常用脚本1 查看所有数据文件select file_name from dba_data_filesunionselect file_name from dba_temp_filesunionselect name from v$controlfileunionselect value from v$parameter where namespfileunionselect member from v$logfile;2 查看正…

柜员计算机技能,新入职柜员必备软件:柜员技能训练系统最新版

如果你是新入职柜员的大学生&#xff0c;这个软件你肯定用得着&#xff01;如果你是资格老的柜员同胞&#xff0c;这个软件你肯定用得着&#xff01;这个软件&#xff0c;针对柜员的小键盘、打字和点钞三项技能要求&#xff0c;专门针对痛点开发&#xff0c;可以有效训练柜员的…

Html5和Css3扁平化风格网页

前言 扁平化概念的核心意义 去除冗余、厚重和繁杂的装饰效果。而具体表现在去掉了多余的透视、纹理、渐变以及能做出3D效果的元素&#xff0c;这样可以让“信息”本身重新作为核心被凸显出来。同时在设计元素上&#xff0c;则强调了抽象、极简和符号化。 示例 视频效果&…

独立线性度 最佳直线

找到的散点线性拟合方法都是基于最小二乘法的&#xff08;numpy.polyfit()&#xff0c;scipy.optimize()) 以下是根据 GB/T 18459-2001中附录 A2 提供的独立线性度拟合方法&#xff0c;求得的最佳拟合直线 import mathdef find_line(x0, y0):根据散点求得端基直线k,b,并得到每点…

第4章 使用 Spring Boot

使用 Spring Boot 本部分将详细介绍如何使用Spring Boot。 这部分涵盖诸如构建系统&#xff0c;自动配置以及如何运行应用程序等主题。 我们还介绍了一些Spring Boot的最佳实践(best practices)。 虽然Spring Boot没有什么特殊之处&#xff08;它只是一个可以使用的库&#xff…

按功能而不是按层打包课程

大多数企业Java应用程序在设计上都有一些相似之处。 这些应用程序的打包通常由它们使用的框架&#xff08;如Spring&#xff0c;EJB或Hibernate等&#xff09;驱动。或者&#xff0c;您可以按功能对打包进行分组。 像其他任何有关建模的项目一样&#xff0c;这也不是没有任何问…

go mod依赖离线安装_Go语言go mod包依赖管理工具使用详解

go modules 是 golang 1.11 新加的特性。现在 1.12 已经发布了,是时候用起来了。Modules 官方定义为: 模块是相关 Go 包的集合。modules 是源代码交换和版本控制的单元。go 命令直接支持使用 modules,包括记录和解析对其他模块的依赖性。modules 替换旧的基于 GOPATH 的方法…

总是助手服务器失败怎么回事,《遇见逆水寒》连接服务器失败解决方法汇总 服务器连接失败问题原因...

导读遇见逆水寒连接服务器失败怎么回事&#xff0c;近期不少小伙伴都在反映遇见逆水寒助手连接服务器失败&#xff0c;一直登不上去是怎么回事&#xff0c;小编这就为大家分享下遇见逆水寒连接服务器失败解决方法。遇见逆水寒连接服务器失败解决方法...遇见逆水寒连接服务器失败…

Linux常用开发环境软件-redis安装

linux下安装redis3.2.11版本  1、安装编译环境 yum install gcc  //安装编译环境 2、到官网下载redis 官网地址&#xff1a;https://redis.io/download 3、用WinScp工具&#xff0c;将下载好的redis-3.2.11.tar.gz传输到linux服务器下的opt目录下(opt就相当于window的d://so…