策略模式

个人博客地址:https://alexaccele.github.io/

策略模式

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

设计原则

设计原则:

  • 找出应用中可能需要变化之处,把它们独立出来,不要和那些不需要变化的代码混在一起。
  • 针对接口编程,而不是针对实现编程。即不需要知道实现细节,只根据接口相关信息编程
  • 多用组合,少用继承。

案例

首先根据面向对象的思想要设计一系列鸭子时,我们会先创建好一个Duck基类,然后在这个基类中添加每个鸭子都会有的行为,例如swim()/quack()/fly()等等行为,于是我们开始给每个子类重写对应的方法,此时若要再添加行为时,我们不仅需要在基类中添加,还要为每个子类添加重写,又或者说是某些子类并不具有基类的全部行为,这时我们可能又要再去修改基类。无论是哪种情况都增加了我们维护和更新功能的负担,策略模式则可以为我们提供一种解决方案,提高代码的重用性。

我们尝试着把一些变化的行为分离出来,例如quack()和fly()
首先是这两个对应方法的接口

分离行为

quack行为的接口:

public interface QuackBehavior {
	void quack();
}

fly行为的接口:

public interface FlyBehavior {
	void fly();
}

根据行为的不同进行实现

在完成了变化行为的分离之后,我们可以针对具体的不同行为提供不同的实现
例如,fly的不同行为可能有不能飞和用翅膀飞两种

用翅膀飞:

public class FlyWithWings implements FlyBehavior {

	@Override
	public void fly() {
		System.out.println("fly with wings");
	}

}

不能飞:

public class FlyNoWay implements FlyBehavior {

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

}

以及quack行为

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

整合

我们来完善以上提到的所有类和接口等
首先是我们的Duck基类

public abstract class Duck {
	FlyBehavior flyBehavior;
	QuackBehavior quackBehavior;
	
	public Duck() {
		
	}

	public abstract void display();
	
	public void performQuack() {
		quackBehavior.quack();
	}
	public void performFly() {
		flyBehavior.fly();
	}
	public void swim() {
		System.out.println("all duck can swim");
	}
}

注意在Duck基类中,有为行为接口类型声明的两个引用变量。

具体子类RubberDuck表示橡胶鸭

public class RubberDuck extends Duck {
	public RubberDuck() {
		quackBehavior = new Quack();
		flyBehavior = new FlyNoWay();
	}

	@Override
	public void display() {
		System.out.println("a rubber duck");
	}

}

具体子类MallardDuck表示野鸭

public class MallardDuck extends Duck {
	
	public MallardDuck() {
		flyBehavior = new FlyWithWings();
		quackBehavior = new Quack();
	}

	@Override
	public void display() {
		System.out.println("a mallard duck");
	}

}

然后我们编写一个测试类Test

public class Test {
	public static void main(String[] args) {
		Duck duck = new RubberDuck();
		duck.performFly();
		duck.performQuack();
		duck.display();
		duck.swim();
		System.out.println("------------");
		Duck duck2 = new MallardDuck();
		duck2.performFly();
		duck2.performQuack();
		duck2.display();
		duck2.swim();
	}
}

于是我们可以看到运行结果:

can't fly
quack quack quack
a rubber duck
all duck can swim
------------
fly with wings
quack quack quack
a mallard duck
all duck can swim

这里可以看出我们实现了不同行为的分离,并且在使用时都是使用的基类以及基类的方法,在使用时与具体的实现相分离了,由此也可以看到策略模式的魅力。

动态设定行为

我们还可以对现在的代码进行进一步的完善,我们可以为Duck基类添加不同行为的set()方法,以实现动态的行为设定

尽管橡皮鸭不会飞,但我们可以通过将它抛在空中,于是它也有了“fly”的能力,因此我们实现一个新的fly行为

public class FlyWithThrow implements FlyBehavior {

	@Override
	public void fly() {
		System.out.println("fly with throw");
	}

}

测试:

public class Test {

	public static void main(String[] args) {
		Duck duck = new RubberDuck();
		duck.performFly();
		duck.setFlyBehavior(new FlyWithThrow());
		duck.performFly();
		duck.performQuack();
		duck.display();
		duck.swim();
		System.out.println("------------");
		Duck duck2 = new MallardDuck();
		duck2.performFly();
		duck2.performQuack();
		duck2.display();
		duck2.swim();
	}

}

结果:

can't fly
fly with throw
quack quack quack
a rubber duck
all duck can swim
------------
fly with wings
quack quack quack
a mallard duck
all duck can swim

可以看到原本不会飞的橡皮鸭通过我们新的行为实现,也能够通过特定的方式进行"fly"了。

总结

让我们回过头来再看看策略模式的定义

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

再看看我们的案例,首先分离出的两种行为fly和quack就是两个算法族,然后其中各自的具体实现就是封装,同一个算法族中的算法可以相互替换,因为接口相同,替换之后也就有了不一样的行为,这样的策略模式使得我们的代码有了更好的重用性。

例如,当我们再需要添加新的鸭子时,可以根据它的不同行为选择不同的算法族,而不用去修改原本已经写好的基类和子类。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值