• 10.JAVA-接口、工厂模式、代理模式、详解


    1.接口定义

    接口属于一个特殊的类,这个类里面只能有抽象方法全局常量  (该概念在JDK1.8之后被打破,在1.8后接口中还可以定义普通方法静态方法,在后续章节会详讲)

    1.1 接口具有以下几个原则

    • 接口通过interface关键字来实现定义
    • 一个子类如果要继承接口的话,则需要通过implements关键字去实现多个接口(多接口之间通过","隔开),从而实现多继承.
    • 接口的子类如果不是个抽象类,则必须要覆写接口的所有抽象方法,才能承认该类实现了这个接口
    • 接口的子对象可以通过向上转型进行实例化操作

    1.2 接下来来个示例,通过Demo类继承InA和InB两个接口

    interface InA                     //接口InA
    {
             public static final String ATTR = "Attribute:InA";
             public abstract void PrintA();
    }
    
    interface InB                     //接口InB
    {
             public static final String ATTR = "Attribute:InB";
             public abstract void PrintB();
    }
    
    class Demo  implements InA,InB 
    {
             public void PrintA()
             {
                      System.out.println(InA.ATTR);        //打印接口A的全局常量
             }
             public void PrintB()
             {
                      System.out.println(InB.ATTR);        //打印接口B的全局常量
             }
    }
    
    public class Test{
             public static void print(InB b)                  //接口支持向上转型
             {
                      b.PrintB();
             }
             public static void main(String args[])
             {
                      Demo d = new Demo();
                      d.PrintA();                    //打印接口A的全局常量
                      print(d);                       //等价于d.PrintB();
             }
    }

    运行打印:

     

    从上面代码可以看出,接口实际上只是表示一种操作标准  ,而接口本身其实是没有操作能力的,需要子类去实现这个操作能力才行.

     

    2.接口的简化定义

    由于接口组成部分是抽象方法全局常量,所以在方法和常量上写不写public结果都一样,并且方法也可以不用abstract修饰,因为接口里的访问权限都是public的,并且方法默认为抽象的,所以InA接口也可以写为下面这样:

    interface InA                     //接口InA
    {
             String ATTR = "Attribute:InA";     //不需要添加public static final
             void PrintA();             //不需要添加public abstract
    }

    3.接口定义注意的地方

    3.1 对于子类或者抽象子类,可以同时继承抽象类以及多个接口,比如:

    class Demo extends A  implements InA,InB{     // Demo子类继承于A类,以及接口inA和inB
             //... ...    //实现所有抽象方法
    }

    3.2 对于一个子接口,可以通过extends来继承多个父接口,比如:

    interface InC extends InA,InB{                 //InC子接口继承父接口inA和inB
             public void funcC();   //定义抽象方法
    }

    3.3 接口不能继承于抽象类,因为extends关键字用于继承同一品种的(接口!=抽象类),而 implements用于继承于接口的(抽象类!=接口),所以无法实现.

     

    4.接口之工厂设计模式Factory

    工厂设计模式,就是说建立一个工厂类,对实现了同一接口的子类们进行统一的实例创建方法,用来提供给用户调用.而用户无需去了解这些对象该如何创建以及如何组织.

    4.1工厂设计示例

    我们以常用的usb为例,首先需要定义一个USB接口,然后写同一接口的子类们(比如:键盘,鼠标,打印机).由于这些子类们都是独立的,所以我们需要在定义一个工厂类UsbFactory,通过一个方法去统一创建他们,如果不写工厂类的话,假如有100多个USB子类,那岂不是全部创建都要100多个不同的new才行?所以需要一个工厂类负责管理这些对象.

    首先定义USB接口和键盘,鼠标子类:

    interface USB           //USB接口
    {
             public void plugin();
             public void out();
    }
    class Keyboard  implements USB
    {
             public void plugin()
             {
                      System.out.println("****插上 usb键盘****");
             }
             public void out()
             {
                      System.out.println("****取出 usb键盘****");
             }
    }
    
    class Mouse  implements USB
    {
             public void plugin()
             {
                      System.out.println("****插上 usb鼠标****");
             }
    
             public void out()
             {
                      System.out.println("****取出 usb鼠标****");
             }
    }

    然后定义UsbFactory工厂类:

    class UsbFactory
    {
             static public USB getInstance(String name)
             {
                      if("keyboard".equals(name))  //是否为键盘
                              return new Keyboard();
                      else if("mouse".equals(name))        //是否为键盘
                              return new Mouse();
                      else
                              return null;
             }
    }

    最后写测试代码:

    public class Test{
             public static void main(String args[])
             {
                              USB usb1 = UsbFactory.getInstance("keyboard");   //获取键盘类
                              usb1.plugin();
                              usb1.out();
    
                              USB usb2 = UsbFactory.getInstance("mouse");    //获取鼠标类
                              usb2.plugin();
             }
    }

    打印如下:

     

    从上面代码可以看出,通过工厂模式,我们可以更加容易地管理多个相同接口的子类们的操作.

    PS:当前工厂模式还是最简单的,在后续学到反射机制泛型后,在讲解. 

    5.代理模式proxy

    代理模式,就是说为一个具体对象提供一个代理对象,该代理对象主要是为了封装具体对象,并且完成与具体对象有关的所有操作.而具体对象只需要负责核心业务.

    5.1 代理设计示例

    我们以生活中的Eat吃为例,首先需要定义一个Eat接口,然后写一个具体类WhatEat(用来指定具体吃什么),但是在生活中,我们如果吃的不是水果,而是蔬菜,则都要有盘子啊,并且吃之前要先去烧菜盛菜,并且吃完后还要洗碗.而这些操作,我们就不能写在WhatEat类里,因为WhatEat类只负责核心业务(吃),所以便有了代理对象(完成与具体对象有关的所有操作),接下来便写一个EatProxy代理节点类来实现这些与WhatEat类操作.

    首先定义Eat接口和具体吃的类(WhatEat):

    interface Eat
    {
             public int TypeVegetable = 0;      //蔬菜
             public int TypeFruit = 1;          //水果
             public void eat(int type);
    }
    
    class WhatEat implements Eat
    {
             public void eat(int type)
             {
                      if(type == Eat.TypeVegetable)
                              System.out.println("*** 吃蔬菜 ***");
                      else
                              System.out.println("*** 吃水果 ***");
             }
    }

    然后定义EatProxy代理节点类:

    class EatProxy implements Eat
    {
             private Eat eatObject;     //代理下的具体对象
    
             public EatProxy(Eat eatObject)
             {
                      this.eatObject = eatObject;
             }
    
             public void eat(int type)                  //吃东西
             {
                      this.eatPrepare(type);
                      this.eatObject.eat(type);
                      this.eatFinish(type);
             }
     
             private void eatPrepare(int type) //吃东西之前的准备工作
             {
                      if(type == Eat.TypeVegetable)
                      {
                              System.out.println("正在烧菜... ...");
                              System.out.println("烧菜完成,正在盛菜");
                              System.out.println("盛菜完成,准备开吃");
                      }
                      else
                      {
                              System.out.println("正在洗水果,削皮中...");
                              System.out.println("削皮完成,准备开吃");
                      }
             }
    
             private void eatFinish(int type) //吃完东西之后的工作
             {
                      if(type == Eat.TypeVegetable)
                      {
                              System.out.println("吃完了,准备洗碗...");
                      }
                      else
                      {
                              System.out.println("吃完了,准备干其它事...");
                      }
             }
    }

    最后写测试代码:

    public class Test{
             public static void main(String args[])
             {
                      EatProxy  proxy = new EatProxy(new WhatEat());
    
                      proxy.eat(Eat.TypeFruit);                 //通过代理节点吃水果
    
                      //分割线
                      System.out.println();
                      System.out.println();
    
                      proxy.eat(Eat.TypeVegetable);             //通过代理节点吃蔬菜
             }
    }

    打印如下所示:

     

    从上面可以看到,我们WhatEat类只需要完成吃(核心业务),可以发现通过代理可以降低不同类之间的依赖性

     6.总结

    学完接口后,它和抽象类之间的区别如下

    区别

    抽象类

    接口

    关键字

    abstract class

    interface

    内部组成

    支持属性,常量,构造方法,普通方法,abstract抽象方法,静态方法等

    支持全局常量,abstract抽象方法

    子类继承

    class 子类 extends 抽象类{

    //... ...

    }

    class 子类 interface 接口1,接口2,...{

    //... ...

    }

    自身继承

    抽象类可以继承于多个接口,或者抽象类.

    接口可以继承多个接口,但不能继承抽象类.

    继承限制

    单继承,一个子类只能继承一个抽象类

    多继承,一个子类可以继承多个接口

    下章学习:11.JAVA-Object类之finalize(),clone(),toString()等方法覆写

  • 相关阅读:
    理解事件驱动select,poll,epoll三种模型
    谈谈对线程与进程的理解
    5-3.首行缩进
    5-2.行高
    5-1.字间距
    4-6.字体样式重置
    4-5.字体风格
    4-4.字体粗细
    4-3.字体颜色设置
    4-2.字体设置
  • 原文地址:https://www.cnblogs.com/lifexy/p/10834971.html
Copyright © 2020-2023  润新知