设计模式学习-策略模式

527 阅读5分钟

策略模式

记录个人学习笔记

前言

设计模式是被发现的,不是被发明出来的,可以认为是经验总结出来的,目的是为了设计提高系统的可维护性 可扩展性 可复用性,做到低耦合 高内聚,模式可以让我们建造出具有良好OO设计质量的系统。

0 定义

定义了算法族,分别封装起来,让他们之间可以相互替换,此模式让算法的变化独立于使用算法的客户

1 前置知识

面向对象的基础

  • 封装

封装的目的是为了保证变量的安全,使用者不必在意具体的细节,而只是通过外部接口即可访问类的成员(一个类有状态和行为去描述事物,个人理解中类本身就是一种事物的抽象)。如果不进行封装,类中的实例变量可以直接查看和修改,这可能给整个系统带来不好的影响,因此在编写类的时候一般将变量私有化,外部类需要使用方法setter和getter访问

  • 多态

多态指的是同一个对象可以表现出多种形态,通俗来说就是一个对象的引用类型既可以是实际类也可以是实际类的子类。

  • 继承

继承实际上也是为了提高代码的复用性和可扩展性,在定义不同类的时候存在一些相同属性,为了方便使用可以将这些共同属性抽象成一个父类,在定义其他子类时可以继承自该父类,减少代码的重复定义,子类可以使用父类中非私有的成员。(在设计模式中,多用组合,少用继承的原则)

2 设计原则

  1. 封装变化:找出应用中可能需要的变化之处,把他们独立出来,不要和那些不变化的代码混在一起。
  2. 多用组合 少用继承
  3. 针对接口编程不针对实现编程

3 策略模式

实例一(错误示范)

我们像看一个简单的实例,鸭子类,首先鸭子会游泳会叫会飞,但是这当中有些变化的元素,在此之前我们理解一下大多数的模式和原则,都是着眼于软件变化的主题的,假如我们的鸭子类不在变化,写一个简单的类就行, 不需要涉及模式,但是如果变化了,这恰恰会体会出模式的魅力,如果我们要增加很多不同的鸭子,如木鸭子、诱饵鸭、橡皮鸭等等,他们的行为是不一样的,比如木鸭子不会叫,也不会飞。下面介绍一个错误的示例: 绘图2.png 这个实例中有一个具体的类Duck,4个子类继承他,由于飞和叫是变化的,所以把他们抽离出来,封装成接口,4个子类都实现这两个接口的方法,但是这个有两个很严重的问题,第一现在只有4个子类,如果100个类,我们就要写200个接口方法,代码复用性差,第二是面向接口编程,而不是面向实现编程,子类都是面向实现去编程的,在用java语言的时候可能会产生一个错误的理解,就是用了interface就是面向接口编程,这是一个错误的观念,我们这里所说的节后,不是特指的java中的interface,而是一个概念,面对超类型编程,也可以这样理解,所以上面这个案例虽然用了接口,但是并不是面向接口编程,子类面向的是实现编程,因为子类要实现接口的代码,怎么算面向对象呢?简单说一种方式,子类可以用构造器,构造器参数是一个接口,调用子类的时候,new 子类(接口实现类),这样子类不用实现方法,而且这样也会提高系统的可维护性。以我现在的理解,组合可以是一个很好的方式,"有一个"比"是一个"要好

实例二(正确示范)

还是上面的例子,我们采用策略模式来编写飞行和叫的算法族 微信图片_20210402100659.jpg 右侧两个方框类就是两个行为的算法族,客户根据需要选择不同的算法,来应对变化。

代码实现

duck类,鸭子类的超类

public abstract class duck{
    FlyBehavior flyBehavior;
    QuacKBehavior quackBehavior;
    public void performFly(){
        flyBehavior.fly();
    }
    public void performQuack(){
        quackBehavior.quack();
    }
    public void swim(){
        System.out.println("All ducks float,enev decoys");
    }
}

飞行算法族

public interface FlyBehavior{
    public void fly();
}
public class FlyWithWing implments FlyBehavior{
    public void fly(){
        System.out.println("I am fly");
    }
}
public class FlyNoWay implments FlyBehavior{
    public void fly(){
        System.out.println("I  can not fly")
    }
}

叫声算法族

public interface QuacKBehavior{
    public void quack();
}
public class Quack implments QuacKBehavior{
    public void quack(){
        System.out.println("Quack");
    }
}
public class MuteQuack implments QuacKBehavior{
    public void fly(){
        System.out.println("MuteQuack");
    }
}
public class Squeak implments QuacKBehavior{
    public void fly(){
        System.out.println("Squeak");
    }
}

测试类

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

4 思想

个人理解,学习一个设计模式不应该记住代码,最重要的是背后的思想,这样才能灵活运用,我们可以仔细的思考,策略模式就做了一件事情,封装变化,策略模式把变化单独的分开。形成一个算法族,算法族有一个统一的接口,当发生改的时候,我们实现接口,就可以在鸭子类中使用,(鸭子类是通过组合的方式使用的接口,两个设计原则的应用),我们想象一个参加过,要改需求,要给木鸭子安装上一个喷气发动机,首先继承Duck类,写出木鸭子类,然后在写一个喷气飞行的类,实现飞行接口,就可以了,这期间我们没有对类的内部进行修改,只是扩展了类。符合开闭原则。所以策略模式的思想就是把变化的部分抽离出来,独立于使用他的类,算法族就是不同的策略。

5 扩展知识

  1. java中方法和变量的权限
  2. 继承涉及到的行为和状态的调用
  3. 多态的向上转型和向下转型
  4. 方法的重写和重载