东方不败希望自己可以文武双全,既能够快意江湖,又可以学富五车,于是改了个名,叫做东方快车。(摘抄的~~)
软件开发一个不变的真理就是:CHANGE 改变
问题归零:继承不能解决问题,因为鸭子的行为在子类里不断地改变,并且让所有的子类都有这些行为是不恰当的。
设计原则一:找出应用中可能需要变化之处,把它们独立出来,不要和那些不需要变化的代码混在一起
把会变化的部分取出并“封装”
通过观察下面超类Duck,找出会变化的部分。
package com.zl.strategy.two;
public abstract class Duck {
public void quack(){//鸭子的叫的方式有很多种,嘎嘎叫,吱吱叫~~ 所以该方法会改变
System.out.println("Duck Quack");
}
public void swim(){
System.out.println("Duck swim");
}
public void fly(){//鸭子飞行会改变,飞与不飞
System.out.println("Duck swim");
}
abstract void display();
}
设计原则二:针对接口编程,而不是针对实现编程
把这些可变的行为放置在一个新的行为接口,然后具体的行为实现该接口即可。
package com.zl.strategy.two;
public interface QuackBehavior {
public void quack();
}
package com.zl.strategy.two;
public interface FlyBehavior {
public void fly();
}
具体实现如下:
package com.zl.strategy.two;
public class Squeak implements QuackBehavior {
@Override
public void quack() {
// TODO Auto-generated method stub
System.out.println("Duck Squeak");
}
}
package com.zl.strategy.two;
public class Quack implements QuackBehavior {
@Override
public void quack() {
// TODO Auto-generated method stub
System.out.println("Duck quack");
}
}
package com.zl.strategy.two;
public class FlyWithWings implements FlyBehavior {
@Override
public void fly() {
// TODO Auto-generated method stub
System.out.println("Duck FlyWithWings");
}
}
package com.zl.strategy.two;
public class FlyNoWays implements FlyBehavior {
@Override
public void fly() {
// TODO Auto-generated method stub
System.out.println("Duck FlyNoWays");
}
}
现在开始重新构造Duck类
Duck类中引入实例变量FlyBehavior,QuackBehavior 并且提供方法进行访问这两个实例变量的方法入口
package com.zl.strategy.two;
public abstract class Duck {
public FlyBehavior tFlyBehavior;
public QuackBehavior tQuackBehavior;
public void swim(){
System.out.println("Duck swim");
}
public void performQuack(){
tQuackBehavior.quack();
}
public void performFly(){
tFlyBehavior.fly();
}
abstract void display();
}
编写一个子类继承Duck:
package com.zl.strategy.two;
public class MallarDuck extends Duck {
public MallarDuck(){
tQuackBehavior=new Quack();
tFlyBehavior=new FlyWithWings();
}
@Override
void display() {
// TODO Auto-generated method stub
System.out.println("MallarDuck display");
}
}
编写测试类:
package com.zl.strategy.two;
public class TestDuck {
/**
* @param args
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
Duck tMallarDuck=new MallarDuck();
tMallarDuck.display();
tMallarDuck.performFly();
tMallarDuck.performQuack();
tMallarDuck.swim();
}
}
此处的一个弊端是,在MallarDuck.java中构造器处对接口进行具体实现类实例化,如果日后鸭子飞行行为,叫行为改变时,就需要修改代码。所以应该进行动态进行实例化具体的实现类。
在Duck.java中添加两个set方法,向外界提供入口,进行传入接口的具体实现类。这里运用了多态。在程序运行时,动态的改变行为。
改造如下:
package com.zl.strategy.two;
public abstract class Duck {
public FlyBehavior tFlyBehavior;
public QuackBehavior tQuackBehavior;
public void swim(){
System.out.println("Duck swim");
}
public void performQuack(){
tQuackBehavior.quack();
}
public void performFly(){
tFlyBehavior.fly();
}
abstract void display();
public void setFlyBehavior(FlyBehavior fly){
tFlyBehavior=fly;
}
public void setQuackBehavior(QuackBehavior quack){
tQuackBehavior=quack;
}
}
测试类如下:
package com.zl.strategy.two;
public class TestDuck {
/**
* @param args
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
Duck tMallarDuck=new MallarDuck();
tMallarDuck.display();
tMallarDuck.performQuack();
tMallarDuck.setQuackBehavior(new Squeak());
tMallarDuck.performQuack();
}
}