java 设计模式之2策略模式

学习设计原则之前先了解java OO基础:

  • 抽象
  • 封装
  • 多态(重点之重)
  • 继承

几个重要面向对象设计原则:

  • 1.面向接口(超类)编程
  • 2.少用继承,多用接口
  • 3.封装变化(将变化的部分封装起来)

一. 一步步开始设计类图

针对鸭子 我们设计类结构及之间的关系。

按照一般的想法,我们会设计一个超类Duck,方法有quack(),swim()等,其他子类鸭子统统继承这个超类Duck,这样子类就不用重新写相关方法,增加了代码复用性。类图如下:

此时如果想增加一个行为fly,把他添加到Duck超类,那么子类同样都可以继承。但是如果有一只玩具鸭他不会飞,那么在超累Duck中添加fly方法,就会有问题了,玩具鸭不该具有的飞行fly行为,却被玩具鸭从Duck类继承了!

你又想到,可以使用继承然后覆盖重写超类的方法,玩具鸭重写fly方法,变成不会飞,这样确实可行!但如果有一只鸭子不会飞,但又会瓜瓜叫,又有一只鸭子会飞但不会瓜瓜叫…如果有类似的鸭子n只,岂不是每个类都需要重写覆盖一些方法么?可见使用继承Duck,这种方式有一些死板,超类Duck的行为,继承的子类不一定都具有Duck的行为,而且代码在子类中都会有重复,且子类鸭子的行为不能轻易改变。

我们说到面向接口编程,少用继承,把变化的部分拿出来封装。那么我们把可能会发生变化的行为 Fly行为和Quak叫的行为都从Duck超类拿出来,形成两个接口。使各种各样的fly的行为,如FlyWithWings,FlyNoWay,或者叫的行为,如Quack方式叫,Squeak方式叫,去实现这两个接口。

这样一来,飞行的行为和叫的行为被单独拿出来了,已经与Duck类无关,弹性增加

上方已经把FlyBeahvior和QuackBeahvior从Duck超类中剥离,那么怎样让Duck类使用到这两个行为呢?采用委托代理的方式,在Duck类中添加这两个接口,通过这两个接口执行具体的fly行为或quack行为。Duck类如图:

子类鸭子如何设定Flybehavior和QuackBehavior的实例呢?

通过构造的方式,来实例化具体的行为(这种方式有些死板,因为具体的行为是静态构造的,稍后我们通过其他方法使之能动态改变)
构造方式如下:

扫描二维码关注公众号,回复: 12440677 查看本文章
/*
这是一直会吱吱叫和会飞行的鸭子
*/
public class OneFlyDuck2 extends Duck {
    
    

        public OneFlyDuck2() {
    
    
                quackBehavior = new QuackWithSqueak(); //
                flyBehavior = new FlyWithWings(); // 用翅膀飞行
        }

}

二.代码编写:

2.1第一次编码实现:

Duck超类:

鸭子都有的固定的属性或者行为
*/
public class Duck {
    
    

    FlyBehavior flyBehavior;   //声明两个行为
    QuackBehavior quackBehavior;
    //都会游泳
    public void swim(){
    
    
        System.out.println("I can swim");
    };// 游泳

    public void performFlyBehavior(){
    
    
        flyBehavior.fly();  //使用flyBeahvior接口代理执行飞的具体行为
    }
    public void performQuackBehavior(){
    
    
        quackBehavior.quack();//使用QuackBehavior接口代理执行叫的具体行为
    }

FlyBehavior:

/*
各种飞的接口 
*/
public interface FlyBehavior{
    
    
    void fly();//各种飞
 
}

QuackBehavior:

/*
叫的接口
*/
public interface QuackBehavior {
    
    
    void quack();//叫
}

FlyWithWings实现FlyBehavior接口:

public class FlyWithWings implements FlyBehavior {
    
    
    @Override
    public void fly(){
    
    
        System.out.println("I fly with Wings!");
    }
}

FlyWithNoWay实现FlyBehavior接口:


public class FlyWithNoWay implements FlyBehavior {
    
    
    @Override
    public void fly(){
    
    
        System.out.println("I fly with noWay!");
    }
}

Squeak实现QuackBehavior接口:

/*
吱吱叫 
*/
public class Squeak implements QuackBehavior{
    
    
    @Override
    public void quack(){
    
    
        System.out.println("I  can Sequack!");  }    
}

Quack叫实现QuackBehavior接口:

/*
瓜瓜叫
*/
public class Quack  implements QuackBehavior {
    
    
    public void quack(){
    
    
        System.out.println("I can Quack!");
    }
}

一个子类鸭子:

/*
这是一直会吱吱叫和会飞行的鸭子
*/
public class OneFlyDuck2 extends Duck {
    
    
        public OneFlyDuck2() {
    
    
                quackBehavior = new Squeak(); //
                flyBehavior = new FlyWithWings(); // 用翅膀飞行
        }
}

测试类:

public static void main(String[] args) {
    
    
       
        Duck oneflyDuck2=new OneFlyDuck2();
        FlyBehavior flyBehavior=new FlyWithWings(); //翅膀飞行
        QuackBehavior quackBehavior1=new Squeak(); //吱吱方式叫
        oneflyDuck2.performFlyBehavior();;  //这种事oneFlyDuck 构造方式创建的
        oneflyDuck2.performQuackBehavior();
}

结果:
在这里插入图片描述

2.2 第二次编码改进

上方是通过子类构造器方式实例化鸭子具有的行为,这样比较僵硬,有一种方式可以动态地set设定鸭子的行为,方式如下:**

在Duck类中新增set方法,设定具体的飞的行为or叫的行为,然后子类中不需要构造了。

新Duck类:

/*
鸭子都有的固定的属性或者行为
*/
public class Duck {
    
    

    FlyBehavior flyBehavior;   //声明两个行为
    QuackBehavior quackBehavior;
    //都会游泳
    public void swim(){
    
    
        System.out.println("I can swim");
    };// 游泳

    public void performFlyBehavior(){
    
    
        flyBehavior.fly();
    }
    public void performQuackBehavior(){
    
    
        quackBehavior.quack();
    }

	//新增的方法
    public void setFlyBehavior(FlyBehavior flyBehavior1){
    
    
        this.flyBehavior=flyBehavior1;
    }
    public void setQuackBehavior(QuackBehavior quackBehavior1){
    
    
       this.quackBehavior=quackBehavior1;
    }
}

新子类:

/*
这是某一种鸭子
*/
public class OneFlyDuck extends Duck{
    
    
}

测试类:

 public static void main(String[] args) {
    
    
 Duck oneflyDuck=new OneFlyDuck();
  		FlyBehavior flyBehavior=new FlyWithWings(); //翅膀飞行  父类接口指向子类引用
        QuackBehavior quackBehavior1=new Squeak(); //吱吱方式叫  父类接口指向子类引用
        oneflyDuck.setFlyBehavior(flyBehavior);//传递会飞的行为
        oneflyDuck.setQuackBehavior(quackBehavior1); //传递会叫的行为。
        oneflyDuck.performFlyBehavior();//执行飞的行为
        oneflyDuck.performQuackBehavior();//执行叫的行为}

结果:
在这里插入图片描述

2.3额外补充

如果新增一只鸭子,他是用火箭实现飞行的,那么只需要新建一个火箭飞行类实现FlyBehavior接口,而不需要修改原有代码.

/*
新增加的飞行方式
*/
public class RocketFly implements FlyBehavior{
    
    
    @Override
    public void fly(){
    
    
        System.out.println("I can fly with Rocket!!");
    }    
}

测试:


    public static void main(String[] args) {
    
    
  		Duck duckRocket=new OneRocketDuck();
        FlyBehavior flyBehavior2=new RocketFly(); //实例化 使用火箭飞的行为
        duckRocket.setFlyBehavior(flyBehavior2);//设定飞的行为 是通过火箭方式
        duckRocket.performFlyBehavior();//执行fly
 }

代码的执行过程:
duckRocket是指向子类的父类引用,因为多态特性,因此duckRocket可以调用在Duck类中的setFlyBehavior方法。
flyBehavior是指向子类的父接口引用,将flybehavior作为参数传入setFlyBehavior方法,就是实例化了Duck类中的flyBehavior。
最后使用duckRocket调用performFlyBehavior方法,就是执行了flyBehavior.fly(),因为多态,且已经第二步实例化了flyBehavior,因此调用的就是RocketFly中的fly方法。

结果:

在这里插入图片描述

三.最终类设计图

以上就是策略模式:

此模式将变化的部分独立出来封装。

猜你喜欢

转载自blog.csdn.net/weixin_43919632/article/details/111189733