本文共 7520 字,大约阅读时间需要 25 分钟。
试想一下,如果写出来的代码如艺术品,那将是多么美妙的一件事。因此,小编该好好学习一下怎么去设计代码了。设计模式这种东西来到世界上已经有相当历史了,可是工作了之后发现真正能用上的还是少数人。在写代码之前认真思考并设计一下,能省去相当一部分维护代码的成本。朋友推荐了《Head First 设计模式 (中文版)》这本书。小编就直接以这本书来打开设计的大门了。在设计之前我们体会一下根据需求的变化,没有设计的代码会让我们手忙脚乱
public abstract class Duck { public void quack() { System.out.println("呱呱叫"); } public void swim() { System.out.println("游泳"); } public abstract void display();}
public class MallardDuck extends Duck { @Override public void display() { System.out.println("外观:绿头"); }}
public class RedheadDuck extends Duck { @Override public void display() { System.out.println("外观:红头"); }}
总结:感觉还是很可以的,感觉以后增加鸭子只要多写个鸭子类就好了。
代码仅仅修改了Duck类
public abstract class Duck { public void quack() { System.out.println("呱呱叫"); } public void swim() { System.out.println("游泳"); } public abstract void display(); public void fly() { System.out.println("飞"); }}
总结:内心觉得当初设计还是有点用的,完美适应增加的需求
public class RubberDuck extends Duck { /** * 覆盖父类方法,实现新的功能 */ @Override public void quack() { System.out.println("吱吱叫"); } @Override public void display() { System.out.println("外观:橡皮鸭"); } @Override public void fly() { //不会飞 }}
public class DecoyDuck extends Duck { @Override public void display() { System.out.println("外观:诱饵鸭"); } @Override public void quack() { // 不会叫 } @Override public void fly() { // 不会飞 }}
总结:这时候随着需求不断增加,感觉当初采用继承的方式去设计代码有点不够用了
public interface Flyable { void fly();}
public interface Quackable { void quack();}
public abstract class Duck { public void swim() { System.out.println("游泳"); } public abstract void display();}
public class RedheadDuck extends Duck implements Flyable, Quackable { @Override public void display() { System.out.println("外观:红头"); } @Override public void fly() { System.out.println("飞"); } @Override public void quack() { System.out.println("呱呱叫"); }}
public class MallardDuck extends Duck implements Flyable, Quackable { @Override public void display() { System.out.println("外观:绿头"); } @Override public void fly() { System.out.println("飞"); } @Override public void quack() { System.out.println("呱呱叫"); }}
public class RubberDuck extends Duck implements Quackable { @Override public void quack() { System.out.println("吱吱叫"); } @Override public void display() { System.out.println("外观:橡皮鸭"); }}
public class DecoyDuck extends Duck { @Override public void display() { System.out.println("外观:诱饵鸭"); }}
总结:使用接口之后发现确实可以不写这么多空实现了,但是也暴露出了另一个问题,
行为:FlyBehavior以及他的不同实现方式:飞,不会飞...
public interface FlyBehavior { void fly();}
public class FlyNoWay implements FlyBehavior { @Override public void fly() { //不会飞 }}
public class FlyWithWings implements FlyBehavior { @Override public void fly() { System.out.println("飞"); }}
行为:QuackBehavior 以及他的不同实现方式:呱呱叫,吱吱叫,不会叫...
public interface QuackBehavior { void quack();}
public class MuteQuack implements QuackBehavior { @Override public void quack() { //什么都不做,不会叫 }}
public class Quack implements QuackBehavior { @Override public void quack() { System.out.println("呱呱叫"); }}
public class Squeak implements QuackBehavior { @Override public void quack() { System.out.println("吱吱叫"); }}
实体鸭子:实体鸭子组合行为,字类实例化具体行为
public abstract class Duck { FlyBehavior flyBehavior; QuackBehavior quackBehavior; public void swim() { System.out.println("游泳"); } public abstract void display(); public void performQuack() { quackBehavior.quack(); } public void performFly() { flyBehavior.fly(); }}
public class MallardDuck extends Duck { public MallardDuck() { quackBehavior = new Quack(); flyBehavior = new FlyWithWings(); } @Override public void display() { System.out.println("外观:绿头"); }}
public class RedheadDuck extends Duck { public RedheadDuck() { quackBehavior = new Quack(); flyBehavior = new FlyWithWings(); } @Override public void display() { System.out.println("外观:红头"); }}
public class RubberDuck extends Duck { public RubberDuck() { quackBehavior = new Squeak(); flyBehavior = new FlyNoWay(); } @Override public void display() { System.out.println("外观:橡皮鸭"); }}
public class DecoyDuck extends Duck { public DecoyDuck() { quackBehavior = new MuteQuack(); flyBehavior = new FlyNoWay(); } @Override public void display() { System.out.println("外观:诱饵鸭"); }}
总结:光从uml上看就能体会到组合的拓展性是多么的强了。重构成这样之后,不用更担心拓展任何的功能的鸭子了,如果没有功能,你就提供接口,并提供实现类,组合到新的鸭子里即可。那么你可能你会说了,这样还是不够动态。如果我要连行为都是动态的呢?
需求:增加一个模型鸭,不会飞,会呱呱叫。但是模型鸭可以变成吱吱叫,并且会用火箭飞
考虑:由于我们将行为当成属性组合到父类里面了,要改变行为,那么提供改变属性的set方法即可。 做法:修改Duck类,增加改变属性flyBehavior、quackBehavior的方法。拓展模型鸭提供默认行为实现。增加fly的实现方式用火箭飞public class FlyRocketPowered implements FlyBehavior { @Override public void fly() { System.out.println("用火箭飞"); }}
public abstract class Duck { FlyBehavior flyBehavior; QuackBehavior quackBehavior; public void swim() { System.out.println("游泳"); } public abstract void display(); public void performQuack() { quackBehavior.quack(); } public void performFly() { flyBehavior.fly(); } /** * 修改行为:FlyBehavior * * @param flyBehavior * @return */ public Duck setFlyBehavior(FlyBehavior flyBehavior) { this.flyBehavior = flyBehavior; return this; } /** * 修改行为:QuackBehavior * * @param quackBehavior * @return */ public Duck setQuackBehavior(QuackBehavior quackBehavior) { this.quackBehavior = quackBehavior; return this; }}
public class ModelDuck extends Duck { public ModelDuck() { quackBehavior = new Quack(); flyBehavior = new FlyNoWay(); } @Override public void display() { System.out.println("外观:模型鸭"); }}
public class Test { public static void main(String[] args) { Duck modelDuck = new ModelDuck(); modelDuck.performQuack(); modelDuck.performFly(); modelDuck.setQuackBehavior(new Squeak()); modelDuck.setFlyBehavior(new FlyRocketPowered()); modelDuck.performFly(); }}
总结:从最初的继承,到接口,到封装改变,面向接口变成。我们已经体会到了设计的美妙。我们发现了这样写出来的代码具有较高的拓展性了。无论是拓展行为,还是拓展实体。都可以驾驭的了。但是如果一开始没有思考和设计,随意设计,一旦项目的代码和业务多起来,那么重构的成本将会提高很多,因此写代码之前花点时间思考一下拓展性是很有必要的。
总结一下这个过程当中的一些设计原则。
将变化的部分和固定部分的区别开来,封装变化
面向接口编程,而不是面向实现编程
组合比继承好用,多用组合,少用继承
《Head First 设计模式 (中文版)》
转载地址:http://xyvdl.baihongyu.com/