设计模式一之策略模式学习笔记

设计模式一之策略模式学习笔记

阅读《Head First设计模式》来学习设计模式,以下代码都是书中的例子,通过不断的优化代码来达到学习的目的。《Head First设计模式》中的完整的代码的例子都可以在https://www.wickedlysmart.com/head-first-design-patterns/下载到。
看书是学习的一种方式,写博客是巩固学习设计模式的另一种方式,以此对学习模式的理解更加深刻。以下从业务需求开始。

需求

某公司设计了一款鸭子游戏。游戏中会有各种鸭子,各种行为,比如游泳,呱呱叫。下面根据需求来设计一下。

开始设计

按照我的正常的逻辑思维,首先要设计一个鸭子超类,他会有很多方法,属性。子类通过继承来得到行为。(哈哈哈,太幼稚了)
在这里插入图片描述

package headfirst.strategy.old;

public abstract class Duck {

	public abstract void quack();
	
	public abstract void swim();
}
package headfirst.strategy.old;

public class MallardDuck extends Duck{
	@Override
	public void quack() {
		System.out.println("Quack");
	}
	@Override
	public void swim() {
		System.out.println("Swim");
	}
}
package headfirst.strategy.old;

public class RedheadDuck extends Duck{
	@Override
	public void quack() {
		System.out.println("Quack");
	}
	@Override
	public void swim() {
		System.out.println("Swim");
	}
}

思考一下,上面的代码可能的问题:

  1. 代码看起来很笨重,每个子类都要重写父类的方法,实现功能。
  2. 如果超类新添加了一个新的方法,每个子类也要重写同样的方法。
  3. 如果父类的方法子类没有这个特性,难道要抛出一个异常或者不管了吗。

设计1

如果鸭子有会飞的方法,但是有的鸭子不会飞怎么办呢。设计如下:
在这里插入图片描述
由于有的鸭子没有fly()的功能,或者橡皮鸭子也没有quack()的功能,我们把这2个行为单独分离出来,写成接口。
把不变的属性和方法封装在类中。容易改变的行为单独创建一个接口类,鸭子子类分别继承鸭子类和行为的接口。
这就涉及到一个设计原则:

找出应用中可能需要变化之处,把它们独立出来,不要和那些不需要变化的代码混在一起。

设计1已经进行了分离,系统变得更有弹性了,但是通过继承而来的方法,每个子类也是需要重写方法来实现fly()的功能和quack()的功能,这个设计是否还可以继续改进呢?

最终设计

从现在开始鸭子的行为被放在单独的类中,这些类专门提供某些接口的实现的功能。
在这里插入图片描述
应用到了设计原则:

多用组合,少用继承。

代码如下:

package headfirst.strategy.recent;

import headfirst.strategy.recent.FlyBehavior;
import headfirst.strategy.recent.QuackBehavior;

public abstract class Duck {
	FlyBehavior flyBehavior;
	QuackBehavior quackBehavior;

	public void setFlyBehavior(FlyBehavior fb) {
		flyBehavior = fb;
	}

	public void setQuackBehavior(QuackBehavior qb) {
		quackBehavior = qb;
	}

	public void performQuack() {
		quackBehavior.quack();
	}

	public void performFly() {
		flyBehavior.fly();
	}

}
package headfirst.strategy.recent;

public class MallardDuck extends Duck {

	public MallardDuck() {
		quackBehavior = new Quack();
		flyBehavior = new FlyWithWings();

	}
}
package headfirst.strategy.recent;

public class RubberDuck extends Duck {
	//默认构造
	public RubberDuck() {
		flyBehavior = new FlyNoWay();
		quackBehavior = new Squeak();
	}
	//有参构造,初始化就可以赋值行为
	public RubberDuck(FlyBehavior flyBehavior, QuackBehavior quackBehavior) {
		this.flyBehavior = flyBehavior;
		this.quackBehavior = quackBehavior; 
	}
 }
package headfirst.strategy.recent;

public interface FlyBehavior {
	public void fly();
}
package headfirst.strategy.recent;

public class FlyWithWings implements FlyBehavior{

	@Override
	public void fly() {
		System.out.println("I'm flying!!");
	}

}
package headfirst.strategy.recent;

public class FlyNoWay implements FlyBehavior{

	@Override
	public void fly() {
		System.out.println("I can't fly");
	}

}

package headfirst.strategy.recent;

public interface QuackBehavior {
	public void quack();
}
package headfirst.strategy.recent;

public class Quack implements QuackBehavior{

	@Override
	public void quack() {
		System.out.println("Quack");
	}

}
package headfirst.strategy.recent;

public class Squeak implements QuackBehavior {
	@Override
	public void quack() {
		System.out.println("Squeak");
	}
}

测试代码如下:

package headfirst.strategy.recent;


public class Test {
	public static void main(String[] args) {
		Duck mallardDuckOne = new MallardDuck();
		mallardDuckOne.performFly();
		mallardDuckOne.performQuack();
		mallardDuckOne.setFlyBehavior(new FlyNoWay());
		mallardDuckOne.performFly();
		System.out.println("========================");
		Duck rubberDuckOne = new RubberDuck(new FlyNoWay(),new Squeak());
		rubberDuckOne.performFly();
		rubberDuckOne.performQuack();
		//改变飞行行为(1)
		rubberDuckOne.setFlyBehavior(new FlyWithWings());
		rubberDuckOne.performFly();
		//再此改变飞行行为(2)
		rubberDuckOne.setFlyBehavior(new FlyNoWay());
		rubberDuckOne.performFly();
	}
}

调用performFly()和performQuack()会打印语句,控制台打印输出如下:
在这里插入图片描述
以上代码应用了策略模式,定义如下:
策略模式定义了算法族,分别封装起来,让他们之间可以互相替换,此模式让算法的变化独立于使用算法的客户。
我的可以行为想象成“一族算法”,把鸭子做的事看成是算法。方法(1)和(2)改变飞机的行为可以看成是改变算法,改变了行为动作。
从以上代码可以看出在使用策略模式过程中的优缺点:

  • 代码提供了公共的策略抽象类,各个抽象类有多个抽象的具体实现类,各个行为分别封装起来。通过组合直接继承行为,代码复用性很高;
  • 修改代码只要修改父类就可以了,子类不需要变动;
  • 可以通过方法动态的改变行为。

缺点:

  • 各个策略抽象类可能会很多,策略的实现类可能就会更多,这些类需要单独记忆,很麻烦;
  • 代码量其实很多。

以上就是策略模式的简单学习,更好的理解还是需要在项目实战中多思考,多实践。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值