当前位置:首页>java>Java 面向对象核心!面向接口编程吃透这篇就够了

Java 面向对象核心!面向接口编程吃透这篇就够了

  • 2026-08-27 10:28:10
Java 面向对象核心!面向接口编程吃透这篇就够了

接口体现的是一种规范和实现分离的设计思想,充分利用接口可极好的降低程序各模块之间的耦合,提高系统的可扩展性和可维护性

## 简单工厂模式

import davieyang.Output;public class Computer{    private Output out;    publicComputer(Output out)    {        this.out = out;    }    // 定义一个模拟获取字符串输入的方法    publicvoidkeyIn(String msg)    {        out.getData(msg);    }    // 定义一个模拟打印的方法    publicvoidprint()    {        out.out();    }}

Computer类已经完全与Printer类分离,只是与Output接口耦合,Computer不再负责创建Output对象,系统提供一个Output工厂来负责生成Output对象

import davieyang.Output;public class OutputFactory{    public Output getOutput()    {        // return new Printer();        return new BetterPrinter();    }    public static void main(String[] args)    {        var of = new OutputFactory();        var c = new Computer(of.getOutput());        c.keyIn("轻量级Java EE企业应用实战");        c.keyIn("疯狂Java讲义");        c.print();    }}

OutputFactory类包含了一个getOutput()方法,该方法返回一个Output实现类的实例,该方法负责创建Output实例,具体创建哪一个实现类的对象由该方法决定(return new Printer();当然也可以有更复杂的逻辑),如果系统需要将Printer改为BetterPrinter实现类,只需要让BetterPrinter实现Output接口,并修改OutputFactory类中的getOutput()方法体即可(return new BetterPrinter();)

import davieyang.Output;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对象使用

把所有生成Output对象的逻辑集中在OutputFactory工厂类中管理,所有需要使用Output对象的类只需要与Output接口耦合,而不是与具体的实现类耦合,即使系统中有很多类使用了Printer对象,我们也只需要修改一处即可实现多处生效,而所有程序无须修改。

## 命令模式

场景:某个方法需要完成某一个行为,但这个行为的具体实现无法确定,必须等到执行该方法时才可以确定,例如假设有个方法需要遍历数组中的数组元素,但无法确定在遍历数组元素时如何处理这些元素,需要在调用该方法时再指定具体的处理行为

对于这样的需求,必须把“处理行为”坐位参数传入该方法

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

Command接口定义了一个process()方法,用于封装“处理行为”,但这个方法没有方法体,因为还无法确定这个处理行为

public class ProcessArray{    publicvoidprocess(int[] target, Command cmd)    {        for (var t : target)        {            cmd.process(t);        }    }}

处理数组的处理类,这个类中包含一个process()方法,这个方法无法确定处理数组的行为,所以定义该方法时使用了一个Command参数,这个Command参数负责对数组的处理行为

通过Command接口,实现了让ProcessArray类与具体的“处理行为”分离,程序使用了Command接口代表了对数组的处理行为

然而Command接口也没有提供真正的处理,只有等到需要调用ProcessArray对象的process()方法时,才真正传入一个Command对象,才确定对数组的处理行为

public class CommandTest{    publicstaticvoidmain(String[] args)    {        var pa = new ProcessArray();        int[] target = {3, -4, 6, 4};        // 第一次处理数组,具体处理行为取决于PrintCommand        pa.process(target, new PrintCommand());        System.out.println("------------------");        // 第二次处理数组,具体处理行为取决于SquareCommand        pa.process(target, new SquareCommand());    }}
public class PrintCommand implements Command{    publicvoidprocess(int element)    {        System.out.println("迭代输出目标数组的元素:" + element);    }}
public class SquareCommand implements Command{    publicvoidprocess(int element)    {        System.out.println("数组元素的平方是:" + element * element);    }}

执行CommandTest结果如下:

迭代输出目标数组的元素:3迭代输出目标数组的元素:-4迭代输出目标数组的元素:6迭代输出目标数组的元素:4------------------数组元素的平方是:9数组元素的平方是:16数组元素的平方是:36数组元素的平方是:16

对于PrintCommand和 SquareCommand两个实现类而言,实际有意义的部分就是process(int[]target)方法,该方法的方法体就是传入ProcessArray类里的process()方法的“处理行为”,通过这种方式就可以实现process()方法和“处理行为”的分离

## 设计模式

设计模式,就是对经常出现的软件设计问题的成熟解决方案,实际上设计模式仅仅是对特定问题的一种惯性思维,要理解设计模式必须以足够的代码积累量作为基础

最新文章

随机文章