@linux1s1s
        
        2017-01-05T09:36:37.000000Z
        字数 4499
        阅读 1774
    Base 2017-01
MallardDuck.java
public class MallardDuck {/*** 鸭子叫的方法*/public void quack() {//TODO}/*** 游泳方法*/public void swim() {//TODO}/*** 外形方法,比如鸭子的颜色*/public void display() {//TODO}}
RedheadDuck.java
public class RedheadDuck {/*** 鸭子叫的方法*/public void quack() {//TODO}/*** 游泳方法*/public void swim() {//TODO}/*** 外形方法,比如鸭子的颜色*/public void display() {//TODO}}
我们发现如果quack()和swim()相同,那么就重复写了两遍相同的代码,增加维护成本的同时也丝毫没有体现出面向对象的思想,所以很自然的将相同的方法抽取到基类里面去。
先给个UML图直观表达一下: 
 
然后看看类的实现:
基类Duck.java
public abstract class Duck {/*** 鸭子叫的方法*/public void quack() {//TODO}/*** 游泳方法*/public void swim() {//TODO}/*** 外形方法,比如鸭子的颜色,交给基类去实现*/public abstract void display();}
子类MallardDuck.java
public class MallardDuck extends Duck {/*** 外形方法,比如鸭子的颜色*/@Overridepublic void display() {//MallardDuck TODO}}
子类RedheadDuck.java
public class RedheadDuck extends Duck {/*** 外形方法,比如鸭子的颜色*/@Overridepublic void display() {//RedheadDuck TODO}}
现在需求突然改动,需要增加一个鸭子的飞翔功能,那么这时我们很庆幸抽取了基类,我们在基类里面增加一个飞翔的方法即可如下: 
基类Duck.java
public abstract class Duck {/*** 鸭子叫的方法*/public void quack() {//TODO}/*** 游泳方法*/public void swim() {//TODO}/*** 飞翔方法*/public void fly(){//TODO}/*** 外形方法,比如鸭子的颜色,交给基类去实现*/public abstract void display();}
如果产品经理又改动了,红嘴鸭子不能飞,这个时候突然意识到自己在基类里面做多了事情,只能在子类中重写基类的fly()方法来补救。
对于上面的设计,你可能发现一些弊端,如果基类有新的特性,子类都必须变动,这是我们开发最不喜欢看到的,一个类变让另一个类也跟着变,这有点不符合OO设计了。这样很显然的耦合了一起。利用继承-->耦合度太高了.
针对上面的问题,我们把容易引起变化的部分提取出来并封装之,来应付以后的变化。虽然代码量加大了,但可用性提高了,耦合度也降低了。
容易变化的部分是quack()和fly()方法,需求很可能从这两个功能变化,所以提取出来两个接口,分别是Flyable.java和Quackable.java,然后基类Duck.java也需要相应的改变,如下所示:

Flyable.java
public interface Flyable {void fly();}
Quackable.java
public interface Quackable {void quack();}
基类Duck.java
public abstract class Duck {/*** 游泳方法*/public void swim() {//TODO}/*** 外形方法,比如鸭子的颜色,交给基类去实现*/public abstract void display();}
子类MallardDuck.java
public class MallardDuck extends Duck implements Quackable {@Overridepublic void display() {//TODO MallardDuck display}@Overridepublic void quack() {//TODO MallardDuck quack}}
子类RedheadDuck.java
public class RedheadDuck extends Duck implements Flyable, Quackable {@Overridepublic void display() {//TODO RedheadDuck display}@Overridepublic void fly() {//TODO RedheadDuck fly}@Overridepublic void quack() {//TODO RedheadDuck quack}}
对上面各方式的总结:
- 继承的好处:让共同部分,可以复用.避免重复编程.
- 继承的不好:耦合性高.一旦超类添加一个新方法,子类都继承,拥有此方法,若子类相当部分不实现此方法,则要进行大批量修改.继承时,子类就不可继承其它类了.
- 接口的好处:解决了继承耦合性高的问题.且可让实现类,继承或实现其它类或接口.
- 接口的不好:不能真正实现代码的复用.可用以下的策略模式来解决.
我们有一个设计原则:
找出应用中相同之处,且不容易发生变化的东西,把它们抽取到抽象类中,让子类去继承它们;
找出应用中可能需要变化之处,把它们独立出来,不要和那些不需要变化的代码混在一起。
现在,为了要分开“变化和不变化的部分”,我们准备建立两组类(完全远离Duck类),一个是"fly"相关的,另一个
是“quack”相关的,每一组类将实现各自的动作。比方说,我们可能有一个类实现“呱呱叫”,另一个类实现“吱吱
叫”,还有一个类实现“安静”。
先来看看UML图:

接下来看源码:
FlyBehavior.java
public interface FlyBehavior {void fly();}
QuackBehavior.java
public interface QuackBehavior {void quack();}
接着是一组实现FlyBehavior接口的具体实现类 
FlyWithWings.java
public class FlyWithWings implements FlyBehavior {@Overridepublic void fly() {//有翅膀的飞行}}
FlyWithNoWings.java
public class FlyWithNoWings implements FlyBehavior {@Overridepublic void fly() {//没有翅膀的飞行}}
然后是一组实现QuackBehavior接口的具体实现类
CroaksQuack.java
public class CroaksQuack implements QuackBehavior {@Overridepublic void quack() {//实现呱呱叫的鸭子}}
SqueakQuack.java
public class SqueakQuack implements QuackBehavior {@Overridepublic void quack() {//实现吱吱叫的鸭子}}
MuteQuack.java
public class MuteQuack implements QuackBehavior {@Overridepublic void quack() {//实现不会叫的鸭子}}
基类聚合了上面的两个接口,成员变量的实例化可以通过构造器,也可以通过Set方法实现。通过这种聚合方式,我们发现不仅大大降低了耦合度,还最大化复用了代码。 
Duck.java
public abstract class Duck {protected FlyBehavior mFly;protected QuackBehavior mQuack;public Duck() {}public Duck(FlyBehavior fly, QuackBehavior quack) {mFly = fly;mQuack = quack;}/*** 鸭子叫的方法*/public void quack() {if (mQuack != null) {mQuack.quack();}}/*** 飞翔方法*/public void fly() {if (mFly != null) {mFly.fly();}}/*** 游泳方法*/public void swim() {//TODO}/*** 外形方法,比如鸭子的颜色,交给基类去实现*/public abstract void display();/*** Get Set 方法** @return*/public FlyBehavior getFly() {return mFly;}public void setFly(FlyBehavior fly) {mFly = fly;}public QuackBehavior getQuack() {return mQuack;}public void setQuack(QuackBehavior quack) {mQuack = quack;}}
然后是两个子类 
MallardDuck.java
public class MallardDuck extends Duck {@Overridepublic void display() {//TODO MallardDuck display}}
RedheadDuck.java
public class RedheadDuck extends Duck {@Overridepublic void display() {//TODO RedheadDuck display}}
最后看一下TestCase
public class TestCase {public static void main(String[] args) {Duck duckFly = new MallardDuck();duckFly.setFly(new FlyWithWings());duckFly.setQuack(new CroaksQuack());Duck duckNoFly = new RedheadDuck();duckNoFly.setFly(new FlyWithNoWings());duckNoFly.setQuack(new SqueakQuack());duckFly.fly();duckFly.quack();duckNoFly.fly();duckNoFly.quack();}}
参考博文 
java常用设计模式 本文做了适当编辑,特别说明。
