美文网首页JavaJavajava
Java 接口--面向对象的精髓

Java 接口--面向对象的精髓

作者: Sia_Coding | 来源:发表于2016-09-29 11:53 被阅读802次

    接口有何用?面试宝典上背下来的总结,你真的明白吗?
    接口&工厂方法 其实很简单>。<~
    本文基于Mars老师的Java4Android视频。

    什么是接口

    先看看生活中的接口,比如USB接口。

    USB接口的设计者在最初就知道USB能支持这么多功能吗?他们是怎样未卜先知地设计的呢?其实他们也不知道以后USB上会连什么设备,他们只是定义了一个数据传输与供电的标准而已。

    Java中也是类似的,定义了接口,就等于定义了调用对象的标准

    接口的基本语法

    • 使用 interface定义;
    • 接口当中的方法都是抽象方法;
    • 接口当中的方法都是public权限(接口中的方法,写不写public修饰符,都是public权限,别的地方不行哦);

    可以把接口理解成一个更加纯粹的抽象类,因此它也不能生成对象。这要怎么办呢?回想抽象类的处理方法,可以用一个类来继承(接口中叫实现)它,从而在子类中生成对象。

    一个最简单的接口示例:

    定义一个接口:

    interface USB {
        public void read(); 
        public void write();
    }
    

    定义它的子类,来实现这个接口:

    class Phone implements USB {
        public void read() {
            System.out.println("Phone --> Read");
        }   
        public void write() {
            System.out.println("Phone --> Write");
        }
    }
    

    测试:

    class Test {
        public static void main(String args []) {
            Phone phone = new Phone();
            //向上转型
            USB usb = phone;
            usb.read();
            usb.write();
        }
    }
    

    运行结果:

    继续了解接口的语法:

    • 实现接口使用implements关键字;
    • 一个类可以实现多个接口;
      实现是特殊的继承,换句话说,就是一个类可以继承多个接口。
      修改上面的代码:

    再定义一个WiFi接口:

    interface WiFi {
        public void open(); 
        public void close();
    }
    
    

    让Phone也实现WiFi接口:

    class Phone implements USB, WiFi {
        public void read() {
            System.out.println("Phone --> Reading");
        }   
        public void write() {
            System.out.println("Phone --> Writing");
        }
        //实现WiFi中的抽象方法
        public void open() {
            System.out.println("WiFi --> Open");
        }   
        public void close() {
            System.out.println("WiFi --> Close");
        }   
    }
    

    测试一下:

    class Test {
        public static void main(String args []) {
            Phone phone = new Phone();
            //向上转型时,就有两种选择
            USB usb = phone;
            usb.read();
            usb.write();
            
            WiFi wifi = phone;
            wifi.open();
            wifi.close();
        }
    }
    

    运行结果:


    可以看到,用USB连接手机时,手机表现的就是USB的行为,用WiFi连接手机时,手机表现的就是WiFi的行为,这也是面向对象多态性非常明显的体现。

    • 一个接口可以继承多个接口
      注意这里不能写成implements,因为我们只想继承USB和WiFi接口的抽象方法,而不想实现它。
    interface SbFi extends USB, WiFi {
        public void piu();
    }
    

    这样SbFi接口就拥有read(),write(),open(),close()和piu()五个抽象方法了:)

    接口的实践

    如果我们接到一个客户的需求,用程序控制办公室中的打印机,我们该怎么做呢?容易想到,先用一个类描述“打印机”,再用一些方法实现“开机”、“关机”、“打印”等动作,一个简单的Printer类就能搞定了。
    可是如果客户提出了新的需求,办公室又买了一台其他品牌的打印机,让你修改之前的代码。这时要怎么做呢?都是打印机,只是品牌不同,功能略有差异,容易想到用接口或者继承。接口更灵活一些,所以我们写出了下面的代码:

    首先定义一个Printer接口,描述打印机都有的行为:

    interface Printer {
        void open();
        void print(String s);
        void close();
    }
    

    在惠普打印机类中,实现Printer中的抽象方法:

    class HPPrinter implements Printer {
        public void open() {
            System.out.println("HP: open");
        }
        public void print(String s) {
            System.out.println("HP: print--> " + s);
        }
        public void close() {
            System.out.println("HP: close");
        }
    }
    

    在佳能打印机中,又增加了新的方法,清洗:

    public class CanonPrinter implements Printer {
        public void open() {
            System.out.println("Canon: open");
        }
        public void print(String s) {
            System.out.println("Canon: print-->" + s);
        }
        public void close() {
            this.clean();
            System.out.println("Canon: close");
        }
        
        public void clean() {
            System.out.println("Canon: clean");
        }
        
    }
    

    测试:
    注意,这里使用对象的向上转型,能减少重复代码。不然就得用HPPrinter和CanonPrinter生成的对象分别调用open, print, close方法,很麻烦。如果以后有100台打印机,岂不是得写300行?(忘记向上转型的话,可以参照我之前写的 对象的转型)。

    class Test {
        public static void main(String args []) {
            Printer printer = null;
            //为简便,flag模拟用户选择使用哪台打印机
            int flag = 1;
            if(flag == 0) {
                //向上转型
                printer = new HPPrinter();
            } else if(flag == 1) {
                printer = new CanonPrinter();
            }
            
            printer.open();
            printer.print("向上转型好用吧~");
            printer.close();
        }
    }
    

    运行:


    大功告成。但是这样就足够了吗?
    如果我们的打印机代码,是在一个办公自动化的系统当中。可能有各种各样的功能,要使用打印机。那每次使用时,都要把Test类中的这一段写一遍吗?如果以后有100个地方要用,岂不是要把这一段写100次?更可怕的是,如果又添加了新的打印机,岂不是要修改这100段代码?太容易出错了。所以,我们和重复代码,是势不两立的(振臂一呼)!

    进击的工厂方法模式

    减少重复代码的一般方法就是,把重复的代码放在一个地方(封装起来),等要用的时候,就调用它,而不是再写一遍。仔细看Test类,重复的地方,不包括最后三行,主要是根据用户的选择,生成打印机对象,并向上转型为Printer类型的部分。

    我们可以设计一个类,在里面添加一个函数,它的功能就是根据用户的选择生成打印机对象,以后我们直接调用这个函数就行了。函数的参数,就是用户的选择,返回值,就是一个Printer类型的对象。

    class PrinterFactory {
        //添加static是为了调用方便
        public static Printer getPrinter(int flag) {
            Printer printer = null;
            if(flag == 0) {
                printer = new HPPrinter();
            } else if(flag == 1) {
                printer = new CanonPrinter();
            }       
            return printer;
        }   
    }
    
    class Test {
        public static void main(String args []) {
            int flag = 1;
            Printer printer = PrinterFactory.getPrinter(flag);
            printer.open();
            printer.print("对象的转型好用吧~");
            printer.close();
        }
    }
    

    这样,就算要增加100台打印机,也只用在PrinterFactory中添加 else if(flag == xxx) 的代码,不用修改Test类。

    这就是著名的简单静态工厂方法模式。
    PrinterFactory并不关心Printer类有多少个子类,这样我们就能够自由地修改Printer子类了。
    工厂方法模式的思路很简单,就是把生成对象的代码,封装在工厂类当中。

    相关文章

      网友评论

      • 黎明未晓:老大,接触Java多久了
        Sia_Coding:@黎明未晓 一年多,我很菜的-。-
      • 鬼兜子:不错不错的。 关于面向对象推荐了解下SOLID原则。关于Phone implements WIFI, USB改成 关联关系has-a是否更合适,Phone有两个属性分别引用WIFI,USB
        Sia_Coding:@鬼兜子 嗯嗯,我还是不够仔细:joy:
      • 小麦子一号:好像工厂方法那边还可以优化
        Sia_Coding:@小麦子一号 嗯,那我明天看看工厂模式:relieved:
        小麦子一号:@Sia_Coding 我也是新人 但是我上次有看到这里 后面他还对工厂类进行了优化
        Sia_Coding:@小麦子一号 能详细点吗~ 我设计模式刚开始看:no_mouth:
      • c43e2ecac515:Mars老师的课讲得非常棒!
        c43e2ecac515:@Sia_Coding 嗯嗯。当初学Android开发的时候,从Mars的Java教程一直看到Android重制版教程。满满的干货啊。
        Sia_Coding:@马三小伙儿 是的!而且视频都是免费的,简直感人
      • 8f2b474da0ff:写的很明白,再接再厉
        Sia_Coding:@奔跑的象宝宝 :relaxed:
      • wblearn:可以了解下swagger,一个接口管理工具
        Sia_Coding:@wblearn 好的,谢谢啦
      • 清荼不解酒的醉:请问一下作者你那个图片使用什么软件画的
        Sia_Coding:@开心就好wcc 嘿嘿
        清荼不解酒的醉:@Sia_Coding 谢谢了,支持你哦
        Sia_Coding:@开心就好wcc 这个是视频里截的,画图的话https://www.processon.com/这个很好用
      • 秋名山菜车手:持续关注!

      本文标题:Java 接口--面向对象的精髓

      本文链接:https://www.haomeiwen.com/subject/edwkyttx.html