1. 模式定义
          把会变化的内容取出并封装起来,以便以后可以轻易地改动或扩充部分,而不影响不需要变化的其他部分;     

 2.模式本质:

     少用继承,多用组合,简单地说就是:固定不变的信息封装在一个类中,变化的信息我们使用接口,抽象定义,那么使用的时候:继承不变的,自定义实现变化的那              部分!

 3.举例分析:    

    

示例:

   一个鸭子类型: 抽象类型

  /*抽象的鸭子类*/
1 public abstract class Duck {
//所有的鸭子均会叫以及游泳,所以父类中处理这部分代码
public void quack() {
System.out.println("嘎嘎嘎.....");
} public void swim() {
System.out.println("游啊游.......");
} //因为每种鸭子的外观是不同的,所以父类中该方法是抽象的,由子类型自己完成。
public abstract void display();
}

  具体鸭子的继承子类:

 public class MallardDuck extends Duck {
//野鸭外观显示为绿头
public void display() {
System.out.println("我是绿头鸭子......");
}
} public class RedHeadDuck extends Duck {
//红头鸭显示为红头
public void display() {
System.out.println("我是红头鸭子......");
}
} public class RubberDuck extends Duck {
//橡皮鸭叫声为嘎嘎嘎叫,所以重写父类以改写行为
public void quack() {
System.out.println("嘎嘎嘎.......");
} //橡皮鸭显示为黄头
public void display() {
System.out.println("我是黄头鸭子.......");
}
}
/***************************【分析说明】***************************************/
上述代码,初始实现得非常好。现在我们如果给Duck.java中加入fly()方法的话,那么在子类型中均有了该方法,于是我们看到了 会飞的橡皮鸭子,你看过吗?    当然,我们可以在子类中通过空实现重写该方法以解决该方法对于子类型的影响。但是父类中再增加其它的方法呢? 通过继承在父类中提供行为,会导致以下缺点: a. 代码在多个子类中重复;
b. 运行时的行为不容易改变;
c. 改变会牵一发动全身,造成部分子类型不想要的改变; /******************************************************************************/

  好啦,还是刚才鸭子的例子,你也许想到使用接口,将飞的行为、叫的行为定义为接口,然后让Duck的各种子类型实现这些接口。

这时侯代码类似于:

 public abstract class Duck {
//将变化的行为 fly() 以及quake()从Duck类中分离出去定义形成接口,有需求的子类中自行去实现 public void swim() {
System.out.println("游啊游.......");
} public abstract void display();
} //变化的 fly() 行为定义形成的接口
public interface FlyBehavior {
void fly();
} //变化的 quack() 行为定义形成的接口
public interface QuackBehavior {
void quack();
} //野鸭子会飞以及叫,所以实现接口FlyBehavior, QuackBehavior
public class MallardDuck extends Duck implements FlyBehavior, QuackBehavior{
public void display() {
System.out.println("我是绿头鸭.......");
} public void fly() {
System.out.println("Fly.");
} public void quack() {
System.out.println("嘎嘎嘎:绿鸭子叫........");
}
} //红头鸭子会飞以及叫,所以也实现接口FlyBehavior, QuackBehavior
public class RedHeadDuck extends Duck implements FlyBehavior, QuackBehavior{
public void display() {
System.out.println("我是红头鸭......");
} public void fly() {
System.out.println("飞呀飞.......");
} public void quack() {
System.out.println("嘎嘎嘎:红鸭子叫");
}
} //橡皮鸭不会飞,但会嘎嘎嘎叫,所以只实现接口QuackBehavior
public class RubberDuck extends Duck implements QuackBehavior{
//橡皮鸭叫声为嘎嘎嘎叫
public void quack() {
System.out.println("嘎嘎嘎:橡皮鸭叫......");
} //橡皮鸭显示为黄头
public void display() {
System.out.println("我是黄头鸭......");
}
}

分析:

上述代码虽然解决了一部分问题,让子类型可以有选择地提供一些行为(例如 fly() 方法将不会出现在橡皮鸭中).但我们也看到,野鸭子MallardDuck.java和红头鸭子RedHeadDuck.java的一些相同行为代码不能得到重复使用。很大程度上这是从一个火坑跳到另一个火坑。
    在一段程序之后,让我们从细节中跳出来,关注一些共性问题。不管使用什么语言,构建什么应用,在软件开发上,一直伴随着的不变的真理是:需要一直在变化。不管当初软件设计得多好,一段时间之后,总是需要成长与改变,否则软件就会死亡。
    我们知道,继承在某种程度上可以实现代码重用,但是父类(例如鸭子类Duck)的行为在子类型中是不断变化的,让所有子类型都有这些行为是不恰当的。我们可以将这些行为定义为接口,让Duck的各种子类型去实现,但接口不具有实现代码,所以实现接口无法达到代码复用。这意味着,当我们需要修改某个行为,必须往下追踪并在每一个定义此行为的类中修改它,一不小心,会造成新的错误。

设计原则:

设计原则:
  把应用中变化的地方独立出来,不要和那些不需要变化的代码混在一起。这样代码变化引起的不经意后果变少,系统变得更有弹性。
    按照上述设计原则,我们重新审视之前的Duck代码。
    1) 分开变化的内容和不变的内容
           Duck类中的行为 fly(), quack(), 每个子类型可能有自己特有的表现,这就是所谓的变化的内容。
           Duck类中的行为 swim() 每个子类型的表现均相同,这就是所谓不变的内容。
       我们将变化的内容从Duck()类中剥离出来单独定义形成接口以及一系列的实现类型。将变化的内容定义形成接口可实现变化内容和不变内容的剥离。其实现类型可实现变化内容的重用。这些实现类并非Duck.java的子类型,而是专门的一组实现类,称之为"行为类"。由行为类而不是Duck.java的子类型来实现接口。这样,才能保证变化的行为独立于不变的内容。

于是我们有:

 //变化的 fly() 行为定义形成的接口
public interface FlyBehavior {
void fly();
} //变化的 fly() 行为的实现类之一
public class FlyWithWings implements FlyBehavior {
public void fly() {
System.out.println("飞呀飞......");
}
} //变化的 fly() 行为的实现类之二
public class FlyNoWay implements FlyBehavior {
public void fly() {
System.out.println("我翅膀受伤了,飞不了......");
}
}
 //变化的 quack() 行为定义形成的接口
public interface QuackBehavior {
void quack();
} //变化的 quack() 行为实现类之一
public class Quack implements QuackBehavior {
public void quack() {
System.out.println("嘎嘎嘎......");
}
} //变化的 quack() 行为实现类之二
public class Squeak implements QuackBehavior {
public void quack() {
System.out.println("吱吱吱.......");
}
} //变化的 quack() 行为实现类之三
public class MuteQuack implements QuackBehavior {
public void quack() {
System.out.println("哑巴,不会叫.......");
}
}
通过以上设计,fly()行为以及quack()行为已经和Duck.java没有什么关系,可以充分得到复用。而且我们很容易增加新的行为, 既不影响现有的行为,也不影响Duck.java。但是,大家可能有个疑问,就是在面向对象中行为不是体现为方法吗?为什么现在被定义形成类(例如Squeak.java)?在OO中,类代表的"东西"一般是既有状态(实例变量)又有方法。只是在本例中碰巧"东西"是个行为。既使是行为,也有属性及方法,例如飞行行为,也需要一些属性记录飞行的状态,如飞行高度、速度等。

整合变化的内容和不变的内容:

 public abstract class Duck {
//将行为类声明为接口类型,降低对行为实现类型的依赖
FlyBehavior flyBehavior;
QuackBehavior quackBehavior; public void performFly() {
//不自行处理fly()行为,而是委拖给引用flyBehavior所指向的行为对象
flyBehavior.fly();
} public void performQuack() {
quackBehavior.quack();
} public void swim() {
System.out.println("游啊游......");
} public abstract void display();
}

Duck.java不关心如何进行 fly()以及quack(), 这些细节交由具体的行为类完成。

 public class MallardDuck extends Duck{
public MallardDuck() {
flyBehavior=new FlyWithWings();
quackBehavior=new Quack();
} public void display() {
System.out.println("Green head.");
}
}

测试类:

 public class DuckTest {
public static void main(String[] args) {
Duck duck=new MallardDuck();
duck.performFly();
duck.performQuack();
}
}

4.思想重点:

  (1)策略思想:
        继承,可以实现静态代码的复用;
     组合,可以实现代码的弹性维护;
     使用组合代替继承,可以使代码更好地适应软件开发完后的需求变化。   (2)策略模式的本质:
      少用继承,多用组合

Java设计模式(学习整理)---策略模式的更多相关文章

  1. Java设计模式学习记录-策略模式

    策略模式 策略模式的定义是:定义了一系列的算法,把它们一个个的封装起来,并且使它们可相互替换,让算法可以独立于使用它的客户而变化. 设计原则是:把一个类中经常改变或者将来可能会经常改变的部分提取出来作 ...

  2. Java设计模式学习记录-状态模式

    前言 状态模式是一种行为模式,用于解决系统中复杂的对象状态转换以及各个状态下的封装等问题.状态模式是将一个对象的状态从该对象中分离出来,封装到专门的状态类中,使得对象的状态可以灵活多变.这样在客户端使 ...

  3. Java设计模式学习记录-模板方法模式

    前言 模板方法模式,定义一个操作中算法的骨架,而将一些步骤延迟到子类中.使得子类可以不改变一个算法的结构即可重新定义该算法的某些特定步骤. 模板方法模式 概念介绍 模板方法模式,其实是很好理解的,具体 ...

  4. Java设计模式学习记录-备忘录模式

    前言 这次要介绍的是备忘录模式,也是行为模式的一种 .现在人们的智能手机上都会有备忘录这样一个功能,大家也都会用,就是为了记住某件事情,防止以后自己忘记了.那么备忘录模式又是什么样子的呢?是不是和手机 ...

  5. Java设计模式学习记录-迭代器模式

    前言 这次要介绍的是迭代器模式,也是一种行为模式.我现在觉得写博客有点应付了,前阵子一天一篇,感觉这样其实有点没理解透彻就写下来了,而且写完后自己也没有多看几遍,上次在面试的时候被问到java中的I/ ...

  6. Java设计模式学习记录-解释器模式

    前言 这次介绍另一个行为模式,解释器模式,都说解释器模式用的少,其实只是我们在日常的开发中用的少,但是一些开源框架中还是能见到它的影子,例如:spring的spEL表达式在解析时就用到了解释器模式,以 ...

  7. Java设计模式学习记录-命令模式

    前言 这次要介绍的是命令模式,这也是一种行为型模式.最近反正没有面试机会我就写博客呗,该投的简历都投了.然后就继续看书,其实看书也会给自己带来成就感,原来以前不明白的东西,书上已经给彻底的介绍清楚了, ...

  8. Java设计模式学习记录-外观模式

    前言 这次要介绍的是外观模式(也称为门面模式),外观模式也属于结构型模式,其实外观模式还是非常好理解的,简单的来讲就是将多个复杂的业务封装成一个方法,在调用此方法时可以不必关系具体执行了哪些业务,而只 ...

  9. Java设计模式学习记录-桥接模式

    前言 这次介绍结构型设计模式中的第二种模式,桥接模式. 使用桥接模式的目的就是为了解耦,松散的耦合更利于扩展,但是会增加相应的代码量和设计难度. 桥接模式 桥接模式是为了将抽象化与实现化解耦,让二者可 ...

  10. Java设计模式之十一 ---- 策略模式和模板方法模式

    前言 在上一篇中我们学习了行为型模式的访问者模式(Visitor Pattern)和中介者模式(Mediator Pattern).本篇则来学习下行为型模式的两个模式,策略模式(Strategy Pa ...

随机推荐

  1. Tcxtreelist动态控制列或行是否能够编辑

    procedure Tfrmaaa.grd1Editing(Sender: TObject; AColumn: TcxTreeListColumn; var Allow: Boolean);begin ...

  2. attitude

    刚看到一段挺有趣的游戏,分享一下. 如果 令 A B C D E F G H I J K L M N O P Q R S T U V W X Y Z 分别等于 1 2 3 4 5 6 7 8 9 10 ...

  3. Bzoj 1696: [Usaco2007 Feb]Building A New Barn新牛舍 中位数,数学

    1696: [Usaco2007 Feb]Building A New Barn新牛舍 Time Limit: 5 Sec  Memory Limit: 64 MBSubmit: 394  Solve ...

  4. A*寻路算法的探寻与改良(二)

    A*寻路算法的探寻与改良(二) by:田宇轩                                                     第二部分:这部分内容主要是使用C语言编程实现A*, ...

  5. C语言实现两栈空间共享

    一个同学让我改一段两栈共享的C语言代码,实现进栈.出栈.输出栈里元素的功能. 代码如下: #include <stdio.h> #include <stdlib.h> #def ...

  6. 自动化运维工具Ansible详细部署 - 人生理想在于坚持不懈 - 51CTO技术博客

    自动化运维工具Ansible详细部署 - 人生理想在于坚持不懈 - 51CTO技术博客 自动化运维工具Ansible详细部署

  7. 让nginx支持文件上传的几种模式

    文件上传的几种不同语言和不同方法的总结. 第一种模式 : PHP 语言来处理 这个模式比较简单, 用的人也是最多的, 类似的还有用 .net 来实现, jsp来实现, 都是处理表单.只有语言的差别, ...

  8. spark 启动时候报 Unable to load native-hadoop library for your platform 警告

    hadoop2.6.4 jdk1.8 spark2.0.1 方案1: 在spark的conf目录下,修改spark-env.sh文件加入LD_LIBRARY_PATH环境变量,值为hadoop的nat ...

  9. 403. Frog Jump

    做完了终于可以吃饭了,万岁~ 假设从stone[i]无法跳到stone[i+1]: 可能是,他们之间的距离超过了stone[i]所能跳的最远距离,0 1 3 7, 从3怎么都调不到7: 也可能是,他们 ...

  10. 用java写随机出题

    import java.io.*; //输入函数包 public class hello{ public static void main(String args[]){ String s=" ...