最近看了郭霖大侠写的设计模式的博客,感觉收获很多,后来自己去看了《Head First设计模式》,也希望自己写一篇博客用来自己以后回顾。
先贴上郭大侠博客
假如有一天接到一个新的项目,要写一个关于飞机的软件。系统中飞机分为战斗机和轰炸机,两种飞机除了外貌不一样都可以飞行和战斗。稍微构思了一下,写出了这样的代码:
public class Plane
{
public Plane()
{
}
public void fight()
{
System.out.println("I can Fight!");
}
public void fly()
{
System.out.println("I can Fly!");
}
}
public class Bomber extends Plane
{
public Bomber()
{
System.out.println("I am Bomber!");
}
}
public class Transport extends Plane
{
public Transport()
{
System.out.println("I am Transport!");
}
}
测试代码如下:
public class Test
{
public static void main(String[] args)
{
Bomber bomber = new Bomber();
bomber.fly();
bomber.fight();
Fighter fighter = new Fighter();
fighter.fly();
fighter.fight();
}
}
测试结果:
I am Bomber!
I can Fly!
I can Fight!
I am Fighter!
I can Fly!
I can Fight!
然后有一天,版本更新了,系统中添加了一个不能战斗的飞机:运输机。稍微构思了一下添加了以下代码
public class Transport extends Plane
{
public Transport()
{
System.out.println("I am Transport!");
}
}
public class Test
{
public static void main(String[] args)
{
Bomber bomber = new Bomber();
bomber.fly();
bomber.fight();
Fighter fighter = new Fighter();
fighter.fly();
fighter.fight();
Transport transport=new Transport();
transport.fly();
transport.fight();
}
}
输出结果如下:
I am Bomber!
I can Fly!
I can Fight!
I am Fighter!
I can Fly!
I can Fight!
I am Transport!
I can Fly!
I can Fight!
通过输出的结果发现忘记了运输机是不能战斗的,稍微思考了一下之后,想到可以重写运输机的战斗方法fight来实现。这个时候开始犯难了,如果以后再增加其他的不能战斗的飞机或者不能飞机的飞机,都要检查并可能需要覆盖Fly和Fight。这在以后维护可能是一个大量的工作,而且可能会产生大量的重复代码。应该怎么办才好呢?
这时候应该使用设计模式“策略模式”。
策略模式定义了一系列的算法,并将每一个算法封装起来,而且使它们还可以相互替换。策略模式让算法独立于使用它的客户而独立变化。
我们知道并非所有的飞机都可以飞行或者战斗,所以继承并不是最适当的方式。虽然重写可以解决不能飞行或者不能战斗的方式,但是这样会产生重复代码,并且效率比较低。我们应该找应用中可能需要变化的地方,把他们独立出来,不要和那些不需要变化的代码混在一起。
我们可以把飞行和战斗作为个属性保存在飞机类里面,然后通过方法调用具体的实现类。
public interface Fly
{
public void PlaneFly();
}
public interface Fighting
{
public void PlaneFighting();
}
将这两个接口保存在飞机类里。通过fight和fly调用具体的实现,同时飞机的外貌可以由Introduction实现。
public abstract class Plane
{
Fighting fighting;
Fly fly;
public abstract void Introduction();
public void fight()
{
fighting.PlaneFighting();
}
public void fly()
{
fly.PlaneFly();
}
}
Fly和Fight实现如下:
public class CanFight implements Fighting
{
@Override
public void PlaneFighting()
{
System.out.println("I can fighting!");
}
}
public class CanFly implements Fly
{
@Override
public void PlaneFly()
{
System.out.println("I can Fly!");
}
}
public class CanNotFight implements Fighting
{
@Override
public void PlaneFighting()
{
System.out.println("I can't fighting!");
}
}
public class CannotFly implements Fly
{
@Override
public void PlaneFly()
{
System.out.println("I cannot Fly!");
}
}
以上四个类就实现了是否可以飞行是否可以战斗四种情况。
public class Bomber extends Plane
{
public Bomber()
{
fighting=new CanFight();
fly=new CanFly();
}
@Override
public void Introduction()
{
System.out.println("I am Bomber!");
}
}
public class Transport extends Plane
{
public Transport()
{
fly = new CanFly();
fighting = new CanNotFight();
}
@Override
public void Introduction()
{
System.out.println("I am Transport!");
}
}
public class Fighter extends Plane
{
public Fighter()
{
fighting = new CanFight();
fly = new CanFly();
}
@Override
public void Introduction()
{
System.out.println("I am Fighter!");
}
}
测试类如下
Plane fighter = new Fighter();
Plane transport = new Transport();
Plane bomber=new Bomber();
fighter.Introduction();
fighter.fight();
fighter.fly();
transport.Introduction();
transport.fight();
transport.fly();
bomber.Introduction();
bomber.fight();
bomber.fly();
结果如下:
I am Fighter!
I can fighting!
I can Fly!
I am Transport!
I can’t fighting!
I can Fly!
I am Bomber!
I can fighting!
I can Fly!
这样每种类别的飞机的功能就实现了,相互之间也没有什么影响,如果系统修改某个功能,只需要修改一个接口的实现类就Ok了。还可以通过一个小技巧动态修改飞机行为。首先在Plane添加Fly和Fight的set方法:
public void setFighting(Fighting fighting)
{
this.fighting = fighting;
}
public void setFly(Fly fly)
{
this.fly = fly;
}
测试方法如下:
Plane transport = new Transport();
for (int i = 0; i < 2; i++)
{
if (i==1)
{
transport.setFighting(new CanFight());
transport.setFly(new CannotFly());
}
transport.fight();
transport.fly();
}
输出结果:
I can’t fighting!
I can Fly!
I can fighting!
I cannot Fly!
以上。
如有不对请指出。