Java 设计模式之策略模式

要想写出可维护、可复用、可扩展的应用程序,就必须掌握一些设计模式的思想.设计模式重在设计,是一种思想层面的东西,需要细细的去领悟。今天学习了一下设计模式的第一个模式——策略模式,现在把它整理出来。

策略模式:定义了算法族,分别封装起来,让他们之间可以互相转换,此模式让算法的变化独立于使用算法的用户。初次去看这么一个定义,估计很多人跟我一样,直接晕掉或者崩溃掉。完全不理解,没关系,我们由一个例子来逐步分析策略模式。

这是一个关于鸭子类的游戏,在这个程序中,会有各种各样的鸭子在水里游泳,呱呱叫等。我们来看代码实现.

<span style="font-family:Courier New;font-size:14px;">/*
 *  鸭子的抽象类 我们定义了一个鸭子超类,他拥有鸭子共同特征的方法,比如呱呱叫,并且拥有一个抽象的方法,因为鸭子有各种各样不同的外观
 */
public abstract class Duck {
	//鸭子呱呱叫
	public void quack() {
		System.out.println("呱呱...");
	}
	//游泳行为
	public void swim() {
		System.out.println("我可以在水里游泳");
	}
	//鸭子外观的抽象方法 
	public abstract void display();
}</span>

<span style="font-family:Courier New;font-size:14px;">/*
 *  外观是绿头的鸭子 继承自超类 Duck那么它也就拥有了超类中的行为,实现超类的抽象方法,以展示自己不同于超类的特征
 */
class MallardDuck extends Duck{

	@Override
	public void display() {
		System.out.println("我是绿头鸭哦");
	}
	
}</span>

<span style="font-family:Courier New;font-size:14px;">/*
 *  外观是红头的鸭子
 */
class ReadheadDuck extends Duck{

	@Override
	public void display() {
		System.out.println("我是红头鸭哦");
	}
	
}</span>

<span style="font-family:Courier New;font-size:14px;">public class DuckTest {
	public static void main(String[] args) {
		MallardDuck md = new MallardDuck();
		md.display();
		md.quack();
		md.swim();
	}
}</span>
这个程序已经写好了,不过好像还没有用到设计模式相关的东西,是的,让我们一步一步的引入策略模式。

现在我们有一个需求,让会飞的鸭子来超越其他的竞争者。如果让我们去实现这样的功能,可能会觉得很简单啊,我们在超类Duck中,写一个飞行类的方法,这样他的子类不就都拥有了飞行行为。恩,确实是这样,但是有一个问题,并不是所有的鸭子都具有飞行行为,比如在这个游戏中会有一些木有鸭子,他们是不会飞甚至不会叫的。那么刚才的做法就会使得不会飞的鸭子也有了飞行的行为,显然是不合适的。

那么我们是不是可以利用接口去达到刚才的需求呢。我们把飞行的行为以及呱呱叫的行为从超类中抽取出来,放到Flyable和Quackable接口中,这样就可以让拥有这些行为的类去实现这些接口.我们来看代码:

<span style="font-family:Courier New;font-size:14px;">/*
 *  鸭子的抽象类
 */
public abstract class Duck {
	//鸭子外观的抽象方法 
	public abstract void display();
	public void swim() {
		System.out.println("游啊游..");
	}
}

/*
 *  外观是绿头的鸭子
 */
class MallardDuck extends Duck implements Quackable,Flyable{

	@Override
	public void display() {
		System.out.println("我是绿头鸭哦");
	}

	@Override
	public void fly() {
		System.out.println("我正在飞哦..");
	}

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

	
	
}
/*
 *  木头鸭 不会飞也不会叫 外观是木头样的颜色 假定因为可以在水上漂 就相当于会游泳
 */
class WoodDuck extends Duck{

	@Override
	public void display() {
		System.out.println("我的外观颜色是木般的颜色");
	}

}
/*
 * 飞行的接口
 */
interface Flyable {
	 void fly();
}
/*
 * 呱呱叫行为的接口
 */
interface Quackable {
	 void quack();
}
public class DuckTest {
	public static void main(String[] args) {
		MallardDuck md = new MallardDuck();
		md.display();
		md.swim();
		md.quack();
		md.fly();
		WoodDuck wd = new WoodDuck();
		wd.swim();
		wd.display();
	}</span>
}

不错,这样是解决了刚才的问题,可以有个问题,那么就是代码的复用性,假设我们有100个鸭子,都有同样的飞行行为,那么这同样的代码我们要在每个子类中写一遍,相当于100遍,即便粘贴复制,也要好久吧.如果要修改的话就更麻烦了。所以从代码复用的角度来看,似乎又不太可行。设计中有一个原则就是:找出应用中可能需要变化的地方,将它们独立出来,与那些不需要变化的代码分离。

从上面的程序分析可知,需要变化的地方是飞行和呱呱叫的行为,因为不同的鸭子具有不同的飞行行为或者是否会呱呱叫。所以根据设计原则,我们应该将他们抽取出来,建立一组新的类来代表每个行为。这里可能有人会有疑问,行为怎么可以成为一个类呢?因为飞行也会有属性,比如飞行的速度,飞行的高度等。或者我们将这个行为类想象成一个技能学习中心,父类中的行为是从这里学习得来的,子类也是。但如果我们要想在鸭子子类中可以动态的去改变飞行的行为,该怎么做?有这样的一个设计原则:针对接口编程,而不是针对实现编程。所以我们用FlyBehavior和QuackBehavior接口来代表每个行为,然后行为的每个实现类都去实现其中的接口。这种做法跟以往不同,我们以往做法是行为来自Duck超类的具体实现,或是继承某个接口并由子去实现,这都是依赖于“实现”,这种做法不灵活。现在我们来看代码实现:

<span style="font-family:Courier New;font-size:14px;">/*
 *  鸭子的抽象类
 */
public abstract class Duck {
	//行为接口的变量
	QuackBehavior quackBehavior;
	FlyBehavior flyBehavior;
	//鸭子外观的抽象方法 
	public abstract void display();
	
	public void performFly() {
		//委托给行为类
		flyBehavior.fly();
	}
	public void performQuack() {
		quackBehavior.quack();
	}
	public void swim() {
		System.out.println("游啊游..");
	}
}
/*
 * 飞行的接口
 */
interface FlyBehavior{
	 public void fly();
}

//飞行的具体实现类
class FlyWithWing implements FlyBehavior {
	public void fly() {
		System.out.println("我会飞哦");
	};
}
class FlyNoWay implements FlyBehavior {

	@Override
	public void fly() {
		System.out.println("我不会飞啊");
	}
	
}
/*
 * 呱呱叫行为的接口
 */
interface QuackBehavior {
	 public void quack();
}
class Quack implements QuackBehavior {
	@Override
	public void quack() {
		System.out.println("呱呱叫");
	}
}
class MuteQuack implements QuackBehavior {

	@Override
	public void quack() {
		System.out.println("我不会叫啊");
	}
	
}
/*
 *  外观是绿头的鸭子
 */
class MallardDuck extends Duck {
	public MallardDuck() {
		flyBehavior = new FlyWithWing();
		quackBehavior = new Quack();
	}
	@Override
	public void display() {
		System.out.println("我是绿头鸭哦");
	}
	
}

/*
 *  木头鸭 不会飞也不会叫 外观是木头样的颜色 假定因为可以在水上漂 就相当于会游泳
 */
class WoodDuck extends Duck{
	public WoodDuck() {
		flyBehavior = new FlyNoWay();
		quackBehavior = new MuteQuack();
	}
	@Override
	public void display() {
		System.out.println("我的外观颜色是木般的颜色");
	}

}
public class DuckTest {
	public static void main(String[] args) {
		//向上转型
		Duck md = new MallardDuck();
		md.display();
		md.performFly();
		md.performQuack();
		Duck wd = new WoodDuck();
		wd.display();
		wd.performFly();
		wd.performQuack();
	}
}</span>
虽然代码量并没有减少,但是可扩展性可维护性是增加的。现在我们虽然在main方法里调用的是同一个方法,但是具体的结果却不同。我们还可以在Duck类里设定一个改变飞行行为或其他行为的方法,这样子类就可以动态的去设定行为了。

设计模式是一种思想,既然是思想上的东西,就需要我们不断的思考,领悟,在实践当中不断的加以运用与验证。虽然写了这篇博客,但并不代表我已经彻底掌握,后面还需要不断的理解、思考并将这些思想运用到实践当中去。

ps:如要转载,请注明出处。另推荐Head First 设计模式这本书,对于初学者来说是一本不错的书,博客中的例子也是引用书里面的。

                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                             


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值