面向接口编程的设计模式

来源:互联网 发布:淘宝909是什么节 编辑:程序博客网 时间:2024/05/01 23:31

面向接口编程的设计模式

简单工厂模式

  • 假设程序中有个Computer类需要组合一个输出设备,现在有两个选择:直接让Computer类组合一个Printer,或者让Computer类组合一个Output,那么到底采用哪种方式更好呢?
  • 假设让Computer类组合一个Printer对象,如果有一天系统需要重构,需要使用BetterPrinter来代替Printer,这就需要打开
    Computer类源代码进行修改。如果系统中只有一个Computer类组合了Printer还好,但如果系统中有100个类组合了Printer,甚至
    1000个、10000个……将意味着需要打开100个、1000个、10000个类进行修改,工作量十分巨大。

为了避免上面的问题发生,工厂模式建议让Computer类组合一个Output类型的对象,将Computer类与Printer类完全分离。Computer对象实际组合的是Printer对象还是BetterPrinter对象,对Computer而言完全透明。当Printer对象切换到BetterPrinter时,系统完全不受影响。代码如下:

public class Computer {    private Output out;    public Computer(Output out) {        this.out = out;    }    // 定义一个模拟获取字符串输入的方法    public void keyIn(String msg) {        out.getData(msg);    }    // 定义一个模拟打印的方法    public void print() {        out.out();    }}
  • 上面的Computer类已经完全与Printer分离,只是与Output接口耦合。Computer不再负责创建Output对象,系统提供一个Output工厂来负责生成Output对象。这个OutputFactory工厂类代码如下:
public class OutputFactory {    public Output getOutput() {        return new Printer();    }    public static void main(String[] args) {        OutputFactory of = new OutputFactory();        Computer c = new Computer(of.getOutput());        c.keyIn("轻量级Java EE企业应用实战");        c.keyIn("疯狂Java讲义");        c.print();    }}
  • 在该OutputFactory类中包含了一个getOutput方法,该方法负责创建Output实例并返回,如果系统需要将Printer改为BetterPrinter实现类,只需要让BetterPrinter实现Output接口,并改变OutputFactory类中的getOutput方法即可。

下面是BetterPrinter实现类的代码,BetterPrinter只是对原有的Printer进行简单修改,以模拟系统重构后的改进。

public class BetterPrinter implements Output {    private String[] printData = new String[MAX_CACHE_LINE * 2];    // 用以记录当前需打印的作业数    private int dataNum = 0;    public void out() {        // 只要还有作业,继续打印        while (dataNum > 0) {            System.out.println("高速打印机正在打印:" + printData[0]);            // 把作业队列整体前移一位,并将剩下的作业数减1            System.arraycopy(printData, 1, printData, 0, --dataNum);        }    }    public void getData(String msg) {        if (dataNum >= MAX_CACHE_LINE * 2) {            System.out.println("输出队列已满,添加失败");        } else {            // 把打印数据添加到队列里,已保存数据的数量加1。            printData[dataNum++] = msg;        }    }}
  • 上面的BetterPrinter类也实现了Output接口,因此也可当成Output对象使用,于是只要把OutputFactory工厂类的getOutput方法修改即可。
  • 再次运行前面的OutputFactory程序,发现系统运行时已经改为BetterPrinter对象,而不再是原来的Printer对象。通过这种方式,即可把所有生成Output对象的逻辑集中在Output工厂类中管理,而所有需要使用Output对象的类只需与Output接口耦合,而不是与具体的实现类耦合。即是系统中有很多类使用了Printer对象,只要OutputFactory类的getOutput方法生的是BetterPrinter对象,则他们全部都会改为使用BetterPrinter对象,而所有程序无需修改每只需要修改OutputFactory工厂类的getOutput方法实现即可。

命令模式

某个方法需要完成某一个行为,但这个行为的具体实现无法确定,必须等到执行该方法时才可以确定。具体一点:假设有个方法需要遍历某个数组的数组元素,但无法确定在遍历时如何处理这些元素,需要在调用该方法时指定具体的处理行为。
这个要求看起来有点奇怪:这个方法不仅需要普通数据可以变化,甚至还有方法执行提也需要变化,难道需要把“处理行为”作为参数传入该方法?
对于这样一个需求,可以考虑使用一个Command接口来定义一个方法,用这个方法来封装“处理行为”。下面是Command接口的代码:

public interface Command {    // 接口里定义的process方法用于封装“处理行为”    void process(int[] target);}

上面的process方法没有方法体,因为还无法确定这个处理行为。
下面是需要处理数组的处理类,在这个处理类中包含一个process方法,这个方法无法确定处理数组的处理行为,所以使用了一个Command参数,这个参数负责对数组的处理行为。

public class ProcessArray {    public void process(int[] target, Command cmd) {        cmd.process(target);    }}

通过一个Command接口,就实现了让ProcessArray和具体处理行为的分离,程序使用Command接口代表类对数组的处理行为。Command接口也没有提供真正的处理,只有等待需要调用ProcessArray对象的process方法是,才真正传入一个Command对象,才确定对数组的处理行为。
下面程序实现了对数组的两种处理方式:

public class CommandTest {    public static void main(String[] args) {        ProcessArray pa = new ProcessArray();        int[] target = { 3, -4, 6, 4 };        // 第一次处理数组,具体处理行为取决于PrintCommand        pa.process(target, new PrintCommand());        System.out.println("------------------");        // 第二次处理数组,具体处理行为取决于AddCommand        pa.process(target, new AddCommand());    }}public class PrintCommand implements Command {    public void process(int[] target) {        for (int tmp : target) {            System.out.println("迭代输出目标数组的元素:" + tmp);        }    }}public class AddCommand implements Command {    public void process(int[] target) {        int sum = 0;        for (int tmp : target) {            sum += tmp;        }        System.out.println("数组元素的总和是:" + sum);    }}
2 0
原创粉丝点击