【Java设计模式】1.策略模式
【Java设计模式】1.策略模式
写在文章的最前面
本人是java小白,自学没多久,在之前学校的课程中学习了java,并对java产生了一定的兴趣,不过只学习了一些最基本的语法。
课上老师给我们提了一个题目,让我们自己去写,当时是写售货机的系统,参考了很多才勉强写出来。后来经同学推荐,开始看设计模式的书,所以想以写博客的方式来激励自己学习,并作一些记录。
本人典型理工科 小白,所以文笔不好,也借此机会锻炼锻炼自己的文笔,有写的语言不通和错误的地方,请大佬勿喷,同为初学者的大家一起交流交流,私信我,再次感激不尽!!
什么是设计模式?
设计模式即为java项目设计中的一种设计方法,通过这些前辈总结的方法以及设计思想,可以让我们在实际java项目开发的时候有规律可循,通过对于具体项目的解剖以及思考,使我们可以对应使用相应的设计模式,大大简化了设计难度,使用科学有效的设计模式,能少走一些不必要的弯路。
问题的引出
现在,我们想要做出一个 “鸭子” 产品,这个鸭子产品拥有下面几个 属性 或 功能 :
- 这个 “鸭子” 它会叫,并且不同的鸭子叫声是不一样的;
- 这个 “鸭子” 它会飞,而且有的鸭子会飞,有的鸭子飞不起来,飞不起来的原因有很多,比如翅膀坏了,又或是这个 “鸭子” 根本没有翅膀,最简单的例子:洗澡的橡皮鸭,对吧!它确实是没有翅膀;
- 这个 “鸭子” 它会呈现给我们一个信息,就像一个按钮,当你按下去的时候,它会告诉你一些东西,可以是关于它是什么鸭子,或者它是否能飞,当然这取决于你,对,就是程序员或者…你的老板(
微笑中透露出了些许无奈,毕竟要恰饭的) 。
第一步,也即最开始的想法
首先创建一个Duck类,这个Duck类包含了一些属性,比如重量、品种、毛皮颜色等,这里可以设置几个以protected为访问控制符的成员变量,变量名称用对应英文即可,例如Weight、Variety、FurColor。
然后就是为Duck这个类创建方法,方法包含了叫、飞以及"自我介绍"的动作。
但是,迎面而来的问题就是,不同的 “鸭子” 拥有不同的属性、行为(即方法),这样当你想创建多个不同鸭子的时候,则要创建对应数量的类。
这样就完全没有运用到代码的复用,不仅复杂而且低效。所以对于代码复用,像我一样的初学者一般想到的就是继承。
个人认为 继承 这个机制有利也有弊,当继承过于复杂时,继承的缺点就暴露出来了,最大的问题就是一个类无法继承两个即两个以上的父类,这就限制了继承的使用。
那么我们先来使用继承父类来试试,首先写一个Duck类,把各种属性以及方法写好,而子类继承父类后,如果子类未进行重写,则方法以及属性仍然默认 “运用” 父类的方法以及属性。
但是我们要编写的是好几个属性以及方法可能不同的 “鸭子” 类。也就意味着代码仍然无法很好的服用,假如多个类之间几乎没有相同的属性以及方法,那继承的属性以及方法基本都是无用的,都要重写,这样代码复用仍然没有很好的实现。
同时,如果这时候,你的老板或者策划突然萌生了一个别的想法,给这些 “鸭子” 加一个动作,比如下蛋,或者迁徙。
这个时候如果要加这样一个方法,那么Duck父类以及下面所有的子类几乎都要手动添加这样一个方法,明显很难实现,在具体工程项目的实践过程中,这样低效率的代码在面临反复多次的修改时会显得很无力,几乎每次修改添加都是重写,而且要重写很多次。
策略模式的引出
因此要解决这样一个问题,即我们要编写一群类,这些类都有一些共通的属性或者方法,这些属性或方法在大的方面属于一类,但每一类都或多或少有些区别,就比如鸭子的叫声有正常鸭子的"呱呱呱"的叫也有橡皮鸭的"叽叽叽"的叫,这都属于发出叫声这样一个行为,但又有所不同,在这种情况下,引用比较专业的说法,就是将这样一种模式细分为下面三种组成:
- 抽象策略角色这个是一个抽象的角色,通常情况下使用接口或者抽象类去实现。对比来说,就是我们的下面代码例子中的FlyBehavior以及QuackBehavior接口。
- 具体策略角色包装了具体的算法和行为。对比来说,就是实现了FlyBehavior以及QuackBehavior接口的实现一组实现类。
- 环境角色内部会持有一个抽象角色的引用,给客户端调用。对比来说,就是我们的具体 “鸭子” 类别。说明:具体的Duck类内部一定会有一个策略类的一个成员变量,这样做的目的在于可以当我们在去创建具体的Duck对象如NormalDuck的时候,可以接收我们向NormalDuck类中传递的具体的策略类。
具体实现代码以及分析
1.Duck抽象类
1 |
|
Duck抽象类中包含了一个抽象的方法display(),用来让鸭子 “声明” 自己的一些信息,或者其他功能,而所有继承Duck抽象类的具体duck类都必须要重写此抽象方法。同时申明了两个抽象策略角色,即flybehavior以及quackbehavior,在后续实例化时,再对这两个变量进行具体的实例化。具体下面代码会解释。
2.FlyBehavior以及QuackBehavior接口
FlyBehavior
1 |
|
QuackBehavior
1 |
|
3.FlyWithWings以及FlyWithoutWings
FlyWithWings
1 |
|
FlyWithoutWings
1 |
|
4.Quack以及CantQuack
Quack
1 |
|
CantQuack
1 |
|
5.normalduck以及modelduck(环境角色)
normalduck
1 |
|
modelduck
1 |
|
以上两个就是环境角色,一个是普通鸭子,另一个是模型鸭子。
总结及分析
- 可以看到,每种不同的鸭子类都可以直接使用已有的一些方法,我们需要做的就是选择当前鸭子类所包含的方法(即行为),当我们想改变这个鸭子类的一种方法,我们只需要将其改为我们提前设定好的一种方法,而不是将代码返工重写,提高了复用率。
- 如果我们想增加一种另一类的方法,比如给鸭子类增加一个 “迁徙” 行为(方法),则我们可以再写接口,即 “迁徙” 接口,然后再对迁徙这个行为具体的实现方式进行实现,比如向南迁徙或向北迁徙,这些"行为类"实现了 “迁徙” 接口。这样我们就可以很方便的给当前已经写好的环境角色类添加行为(方法)
本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!