面向接口编程的设计模式

    xiaoxiao2021-03-25  64

    面向接口编程的设计模式

    简单工厂模式

    假设程序中有个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); } }
    转载请注明原文地址: https://ju.6miu.com/read-40522.html

    最新回复(0)