文章目录
设计原则之封装
找出应用中可能需要变化之处,把它们独立出来,不要和那些不需要变化的代码混在一起。
把会变化的部分取出并“封装”起来,好让其他部分不会受到影响。
换句话说,如果每次新的需求一来,都会使某方面的代码发生变化,那么你就可以确定,这部分的代码需要被抽出来,和其他稳定的代码有所区分。 下面是这个原则的另一种思考方式:“把会变化的部分取出并封装起来,以便以后可以轻易地改动或扩充此部分,而不影响不需要变化的其他部分”。 这样的概念很简单,几乎是每个设计模式背后的精神所在。所有的模式都提供了一套方法让“系统中的某部分改变不会影响其他部分”
设计原则之接口编程
针对接口编程,而不是针对实现编程
“针对接口编程”真正的意思是“针对超类型(super type)编程”。 这里所谓的“接口”有多个含义,接口是一个“概念”,也是一种Java的interface构造。你可以在不涉及Java interfacek的情况下,“针对接口编程”,关键就在多态。利用多态,程序可以针对超类型编程,执行时会根据实际状况执行到真正的行为,不会被绑死在超类型的行为上。“针对超类型编程”这句话,可以更明确地说成“变量的声明类型应该是超类型,通常是一个抽象类或者是一个接口,如此,只要是具体实现此超类型的类所产生的对象,都可以指定给这个变量。这也意味着,声明类时不用理会以后执行时的真正对象类型!
看看下面这个简单的多态例子:假设有一个抽象类Animal,有两个具体的实现(Dog与Cat)继承Animal。做法如下:
-

-
针对实现编程
-
Dog dog = new Dog(); dog.bark(); -
声明变量“d”为Dog与类型(是Animal的具体实现),会造成我们边须针对具体实现编码。
-
-
针对接口/超类型编程
-
Animal animal = new Dog(); animal.makeSound(); -
我们知道实际的子类型是Dog,但是我们现在利用animal进行多态调用。
-
鸭子的故事
类图

具体实现
Duck
package com.example.source.strategy;
public abstract class Duck {
FlyBehavior flyBehavior;
QuackBehavior quackBehavior;
public Duck() {
}
public void setFlyBehavior(FlyBehavior fb) {
flyBehavior = fb;
}
public void setQuackBehavior(QuackBehavior qb) {
quackBehavior = qb;
}
abstract void display();
public void performFly() {
flyBehavior.fly();
}
public void performQuack() {
quackBehavior.quack();
}
public void swim() {
System.out.println("All ducks float, even decoys!");
}
}
DecoyDuck
package com.example.source.strategy;
public class DecoyDuck extends Duck {
public DecoyDuck() {
setFlyBehavior(new FlyNoWay());
setQuackBehavior(new MuteQuack());
}
public void display() {
System.out.println("I'm a duck Decoy");
}
}
RedHeadDuck
package com.example.source.strategy;
public class RedHeadDuck extends Duck {
public RedHeadDuck() {
flyBehavior = new FlyWithWings();
quackBehavior = new Quack();
}
public void display() {
System.out.println("I'm a real Red Headed duck");
}
}
ModelDuck
package com.example.source.strategy;
public class ModelDuck extends Duck {
public ModelDuck() {
flyBehavior = new FlyNoWay();
quackBehavior = new Quack();
}
public void display() {
System.out.println("I'm a model duck");
}
}
RubberDuck
package com.example.source.strategy;
public class RubberDuck extends Duck {
public RubberDuck() {
flyBehavior = new FlyNoWay();
//quackBehavior = new Squeak();
quackBehavior = () -> System.out.println("Squeak");
}
public RubberDuck(FlyBehavior flyBehavior, QuackBehavior quackBehavior) {
this.flyBehavior = flyBehavior;
this.quackBehavior = quackBehavior;
}
public void display() {
System.out.println("I'm a rubber duckie");
}
}
FlyBehavior
package com.example.source.strategy;
public interface FlyBehavior {
public void fly();
}
FlyRocketPowered
package com.example.source.strategy;
public class FlyRocketPowered implements FlyBehavior {
public void fly() {
System.out.println("I'm flying with a rocket");
}
}
FlyNoWay
package com.example.source.strategy;
public class FlyNoWay implements FlyBehavior {
public void fly() {
System.out.println("I can't fly");
}
}
QuackBehavior
package com.example.source.strategy;
public interface QuackBehavior {
public void quack();
}
Squeak
package com.example.source.strategy;
public class Squeak implements QuackBehavior {
public void quack() {
System.out.println("Squeak");
}
}
MuteQuack
package com.example.source.strategy;
public class MuteQuack implements QuackBehavior {
public void quack() {
System.out.println("<< Silence >>");
}
}
Quack
package com.example.source.strategy;
public class Quack implements QuackBehavior {
public void quack() {
System.out.println("Quack");
}
}
Test
package com.example.source.strategy;
public class MiniDuckSimulator1 {
public static void main(String[] args) {
Duck mallard = new MallardDuck();
mallard.performQuack();
mallard.performFly();
Duck model = new ModelDuck();
model.performFly();
model.setFlyBehavior(new FlyRocketPowered());
model.performFly();
}
}
文章介绍了软件设计中的两个重要原则:封装和面向接口编程。通过鸭子的故事展示了如何使用策略模式来实现代码的解耦,使得鸭子的不同行为(飞行和叫声)可以通过更换行为策略来动态改变,而不影响鸭子类本身。文中给出了Duck、FlyBehavior和QuackBehavior等类的实现,以及如何通过设置不同的行为实现不同的鸭子行为效果。

被折叠的 条评论
为什么被折叠?



