0.什么是设计模式?
我们经常使用被人设计好的库和框架,利用他们的API(Application Programming Interface)编写我们的程序,但是我们得把它们“组合”起来。像小孩搭积木一样,建成自己的大厦。其中你用到的“方式”,都是事先存在你脑海中的,这些“方式”都是抽象的,并不是一块块具体的积木。并且,你在搭建的过程中,希望搭建成的玩具简洁,美观,安全,可扩展性强…等等,都是基于你脑海中的“方式”而完成的。这些“方式”.是你在搭建过程中,所经历的成功,失败和借鉴别人的大厦得来的。这些“方式”就称为设计模式。
设计模式比库的等级更高,它将告诉我们如何组织类和对象解决问题。当然,在java优秀的类和库中,也用到了设计模式,这就是源码优秀的原因。这些优秀的设计模式被记录下来,从而知道我们的思想。
为什么一再强调脑海中呢? 当然需要,首先你的脑海中要有基本的模式,才能在实现过程中写出好的设计。
1.什么是策略模式?
OO即(Object Oriented)面向对象。了解过高级语言的同学都知道,OOP(Object Oriented Programming)即面向对象编程,是重头戏。它的特征包括抽象,封装,继承,多态。
策略模式——定义算法族,分别封装起来,让它们之间可以互相独立替换,此模式让算法的变化独立于使用算法的客户。
乍一看非常晦涩难懂,待我们举一个小栗子,大家就会明白了
首先我们要了解几个必要的原则:
(0)封装变化:找出程序中会变化的方面,然后将其和固定不变的方面相分离。
(1)多用组合(combination),少用继承
(2)针对接口编程,不针对实现编程。
这3个原则非常管用,将贯穿我们整个设计模式的学习过程当中。
下面开始最精彩的部分,你将体验到设计模式的魅力。
先从简单的一个实现开始,公司要求你做一个鸭子系统。鸭子我们都知道,一边游泳,一边呱呱叫。同时按特性还分为各种的鸭子,比如红头鸭子,绿头鸭子。按材料分:真鸭子,橡皮鸭(不会飞,吱吱叫),木头鸭子(不会飞,不会叫)
这并不难
现在我们要让鸭子会飞 ,“理所当然”我们将在鸭子类中添加代码:
:
继承了鸭子类的橡皮鸭有个小功能“吱吱叫”(这不难,复写父类即可),但是随之而来的问题出现了:橡皮鸭也飞了起来!
同时,如果有木头鸭子。继承了鸭子类的木头鸭也具备了 “飞”和“叫”的功能!这是完全错误的。
作为一个优秀的OO程序猿,这也不难:我们继续复写!
当有了第四种鸭子(不会飞,会叫),复写!
第五种鸭子(会飞,不会叫),复写!
第六种…第七种….
这样写至少会带来几个问题:
A.代码在多个子类中重复
B.改变父类,造成其他鸭子不要的改变(比如木鸭子不要飞)
所以我们带来了一个原则来拯救你:分开变化和不会变化的部分:
我们在利用第二个原则:针对接口编程
如:我们用Flyable和Quackable接口
紧接着我们实现这两个接口:
现在,父类鸭子将飞行和叫动作“委托”(delegate)别人处理,而不是在父类中定义Duck的方法,在父类中,我们不关心叫接口的对象到底是什么,我们只关心
该对象知道如何实现叫就够了。
好了,讲到这里,我们来写一写代码:
//鸭子父类
public abstract class Duck {
FlyBehavior flyBehavior;
QuackBehavior quackBehavior;
public Duck(){
}
public abstract void display();
public void performFly(){
flyBehavior.fly();
}
public void performQuack(){
quackBehavior.quack();
}
public void swim() {
System.out.println("All duck float,even ddecoys!");
}
}
//定义FlyBehavior 接口
public interface FlyBehavior{
public void fly();
}
//实现FlyBehavior接口
public class FlyNoWay implements FlyBehavior {
public void fly() {
System.out.println("I cannot fly");
}
}
public class FlyWithWings implements FlyBehavior {
public void fly() {
System.out.println("I am flying!");
}
}
//定义QuackBehavior接口
public interface QuackBehavior {
public void quack();
}
//实现QuackBehavior接口
public class Quack implements QuackBehavior {
public void quack() {
System.out.println("Quack");
}
}
public class MuteQuack implements QuackBehavior{
public void quack() {
System.out.println("<<Silence>>");
}
}
public class Squeak implements QuackBehavior{
public void quack() {
System.out.println("Squak");
}
}
//公司让你创建的鸭子
public class MallardDuck extends Duck{
public MallardDuck () {
quackBehavior = new Quack();
flyBehavior = new FlyWithWings();
}
public void display(){
System.out.println("I am a real Mallard duck");
}
}
//测试单元
public class MiniDuckSimulator{
public static void main(String[] arg) {
Duck mallard = new MallardDuck();
mallard.performQuack();
mallard.performFly();
}
}
//输出结果
Quack
I am flying!
另外,我们还可以动态设定行为,在鸭子运行时的行为也可以改变。这也是最开始的继承方法中所没有的。
在Duck类中,加入两个新方法:
public void setFlyBehavior(FlyBehavior fb)
{
flyBehavior = fb;
}
public void setQuackBehavior(QuackBehavior qb)
{
qucakBehavior = qb;
}
// 新建一个鸭子
public class MallardDuck extends Duck{
public MallardDuck () {
quackBehavior = new Quack();
flyBehavior = new FlyWithWings();
}
public void display(){
System.out.println("I am a model duck");
}
}
//实现FlyBehavior接口
public class FlyRocketPowered implements FlyBehavior{
public void fly(){
System.out.println("i am flying with a rocket!");
}
}
//测试单元
public class MiniDuckSimulator{
public static void main(String[] arg) {
Duck model= new ModelDuck();
model.performFly();
model.setFlyBehavior(new FlyRocketPowered());
model.performFly();
}
}
//运行结果
I cannot fly
i am flying with a rocket!