抽象类和接口的应用----常用设计模式总结

来源:互联网 发布:淘宝个体营业执照办理 编辑:程序博客网 时间:2024/06/04 18:18

抽象类和接口是Java面向对象中最重要的概念,如果说不懂抽象类和接口,那么对于面向对象的理解就是0分。

1,为抽象类和接口实例化

在Java中,可以通过对象的多态性为抽象类和接口实例化,这样
在使用抽象类和接口的时候就可以调用子类所覆写过的方法。

之所以抽象类和接口不能直接实例化是因为其内部包含了抽象方法,
抽象方法都是未实现的方法,无法直接调用。

通过对象多态性可以发现,子类发生了向上转型之后,所调用的全部方法
都是被覆写过的方法。

abstract class A{   // 定义抽象类A    public abstract void print() ;  // 定义抽象方法print()};class B extends A { // 定义子类,继承抽象类    public void print(){        // 覆写抽象方法        System.out.println("Hello World!!!") ;    }};public class AbstractCaseDemo01{    public static void main(String args[]){        A a = new B() ;     // 通过子类为抽象类实例化        a.print() ;    }};

这里写图片描述

interface A{    // 定义接口A    void print() ;  // 定义抽象方法print()};class B implements A {  // 定义子类,实现接口    public void print(){        // 覆写抽象方法        System.out.println("Hello World!!!") ;    }};public class InterfaceCaseDemo01{    public static void main(String args[]){        A a = new B() ;     // 通过子类为抽象类实例化        a.print() ;    }};

这里写图片描述

要使用抽象类和接口就得按照这样的使用方式进行(通过子类进行使用),否则是无法进行使用的。

2,抽象类的应用—-定义模板

2-1:场景1,

这里写图片描述

abstract class Person{    private String name ;       // 定义name属性    private int age ;           // 定义age属性    public Person(String name,int age){        this.name = name ;        this.age = age ;    }    public String getName(){        return this.name ;    }    public int getAge(){        return this.age ;    }    public void say(){      // 人说话是一个具体的功能        System.out.println(this.getContent()) ; // 输出内容    }    public abstract String getContent() ;   // 说话的内容由子类决定};class Student extends Person{    private float score ;    public Student(String name,int age,float score){        super(name,age) ;   // 调用父类中的构造方法        this.score = score ;    }    public String getContent(){        return  "学生信息 --> 姓名:" + super.getName() +                 ";年龄:" + super.getAge() +                 ";成绩:" + this.score ;    }};class Worker extends Person{    private float salary ;    public Worker(String name,int age,float salary){        super(name,age) ;   // 调用父类中的构造方法        this.salary = salary ;    }    public String getContent(){        return  "工人信息 --> 姓名:" + super.getName() +                 ";年龄:" + super.getAge() +                 ";工资:" + this.salary ;    }};public class AbstractCaseDemo02{    public static void main(String args[]){        Person per1 = null ;    // 声明Person对象        Person per2 = null ;    // 声明Person对象        per1 = new Student("张三",20,99.0f) ; // 学生是一个人        per2 = new Worker("李四",30,3000.0f) ;    // 工人是一个人        per1.say() ;    // 学生说学生的话        per2.say() ;    // 工人说工人的话    }};

**分析:

1,说话这个功能,正常的是个人都有这个功能,所以可以抽取出来,在Person这个类中,定义一个say()方法,但是说话的内容,不同的类型的人讨论的话题不同,这个话题,不能写成具体的,需要定义成一个抽象的方法,在不同的子类中实现不同的内容。

2,一个人,无论是工人还是学生或者其他什么人,想说话么,想说话,就覆写我的getContent()方法,就是这样规定好了,这就是模板,

2-2:场景2,

这里写图片描述

3,接口的应用—-

3-1,制定标准。

3-2,将方法的视图暴露给远程的客户端(分布式应用中)。

场景

这里写图片描述

interface USB{      // 定义了USB接口,制定标准    public void start() ;   // USB设备开始工作    public void stop() ;    // USB设备结束工作}class Computer{    public static void plugin(USB usb){ // 电脑上可以插入USB设备,只要符合usb接口就可以插入        usb.start() ;        System.out.println("=========== USB 设备工作 ========") ;        usb.stop() ;    }};class Flash implements USB{    public void start(){    // 覆写方法        System.out.println("U盘开始工作。") ;    }    public void stop(){     // 覆写方法        System.out.println("U盘停止工作。") ;    }};class Print implements USB{    public void start(){    // 覆写方法        System.out.println("打印机开始工作。") ;    }    public void stop(){     // 覆写方法        System.out.println("打印机停止工作。") ;    }};public class InterfaceCaseDemo02{    public static void main(String args[]){        Computer.plugin(new Flash()) ;        Computer.plugin(new Print()) ;    }};

这里写图片描述

4,工厂设计模式(接口的应用)

是Java中最长使用的一种设计模式,工厂有什么用呢?

interface Fruit{    // 定义一个水果接口    public void eat() ; // 吃水果}class Apple implements Fruit{    public void eat(){        System.out.println("** 吃苹果。") ;    }};class Orange implements Fruit{    public void eat(){        System.out.println("** 吃橘子。") ;    }};public class InterfaceCaseDemo03{    public static void main(String args[]){        Fruit f = new Apple() ; // 实例化接口        f.eat() ;    }};

主方法相当于一个客户端,主方法的代码越说越好。此时,直接在主方法中
指定了要操作的子类,如果要修改子类,肯定要修改客户端。就是说,现在
系统和特定的子类紧密的耦合在一起了,必须要进行解耦和,否则在扩展的
时候,会遇到想象不到的困难。

分析

这里写图片描述

客户端通过一个过渡段,找到特定的子类,客户端寻找特定子类的操作以

接口为标准。这个过渡段,在程序中就称为工厂设计。

interface Fruit{    // 定义一个水果接口    public void eat() ; // 吃水果}class Apple implements Fruit{    public void eat(){        System.out.println("** 吃苹果。") ;    }};class Orange implements Fruit{    public void eat(){        System.out.println("** 吃橘子。") ;    }};class Factory{  // 定义工厂类    public static Fruit getInstance(String className){        Fruit f = null ;        if("apple".equals(className)){  // 判断是否要的是苹果的子类            f = new Apple() ;        }        if("orange".equals(className)){ // 判断是否要的是橘子的子类            f = new Orange() ;        }        return f ;    }};public class InterfaceCaseDemo04{    public static void main(String args[]){        Fruit f = Factory.getInstance("apple") ;    // 实例化接口        f.eat() ;    }};

客户端通过工厂类取得子类对象,工厂类里面通过判断,实例化对应的子类对象,
返回给工厂,然后向上转型之后再,返回接口对象给客户端,之后,客户端通过
接口对象调用接口中的方法,这样就完成了代码的整个操作过程。
这里写图片描述

这是简单的工厂的使用,但是这里还是存在缺陷,比如,首先,传入的字符串不是”apple”,又不是”orange”,此时返回的Fruit对象是null,就出现问题了,其次,这种字符串的比较方式,在客户端将这个字符串固定死了,程序缺乏灵活性了,

这两个缺陷,也是有解决办法的,这里先不赘述了,参考我的这一片博客,工厂模式

5,代理设计模式(接口的应用)

1场景

这里写图片描述

场景2

这里写图片描述

分析

这里写图片描述

interface Network{    public void browse() ;  // 浏览}class Real implements Network{    public void browse(){        System.out.println("上网浏览信息") ;    }};class Proxy implements Network{    private Network network ;   // 代理对象    public Proxy(Network network){        this.network = network ;    }    public void check(){        System.out.println("检查用户是否合法。") ;    }    public void browse(){        this.check() ;        this.network.browse() ; // 调用真实的主题操作    }};public class ProxyDemo{    public static void main(String args[]){        Network net = null ;        net  = new Proxy(new Real()) ;//  指定代理操作        net.browse() ;  // 客户只关心上网浏览一个操作    }};

这里写图片描述

分析

首先定义一个标准(接口)Network,功能就是浏览;然后,Real是真正的上网服务器,
功能是上网,她实现NetWork接口,并实现接口中的浏览方法,实现真正的浏览功能;然后,
Proxy是代理服务器,功能也是上网,实现Network接口,首先给出代理对象,在实现上网功能之前,完成了其他功能,
比如,进行用户是否合法的判断,然后再实现的network的接口中,执行代理服务器的所有功能。
代理服务器,除了代理其主要功能外,还做了一些与其主要功能相关的功能,这就是代理,完成的更多的功能,(主要功能是从委托类中代理来的
,相关功能在代理类中自己定义的这些相关的功能,被代理类中是不想做这些工作的,所以放在代理类中进行)
这里写图片描述

6,适配器设计模式(接口和抽象类的应用)

该模式在图形Java界面的编程上使用的比较多,在Android的开发中使用的是最多的。

场景:

这里写图片描述

这里写图片描述

interface Window{       // 定义Window接口,表示窗口操作    public void open() ;    // 打开    public void close() ;   // 关闭    public void activated() ;   // 窗口活动    public void iconified() ;   // 窗口最小化    public void deiconified();// 窗口恢复大小}abstract class WindowAdapter implements Window{    public void open(){} ;  // 打开    public void close(){} ; // 关闭    public void activated(){} ; // 窗口活动    public void iconified(){} ; // 窗口最小化    public void deiconified(){};// 窗口恢复大小};class WindowImpl extends WindowAdapter{    public void open(){        System.out.println("窗口打开。") ;    }    public void close(){        System.out.println("窗口关闭。") ;    }};public class AdapterDemo{    public static void main(String args[]){        Window win = new WindowImpl() ;        win.open() ;        win.close() ;    }};

这里写图片描述

7,内部类扩展

抽象类中可以包含若干个接口。接口中也可以定义若干抽象类。

7-1,抽象类内部包含接口

不实现内部接口

abstract class A{   // 定义抽象类    public abstract void printA() ; // 抽象方法    interface B{    // 定义内部接口        public void printB() ;  // 定义抽象方法    }};class X extends A{  // 继承抽象类    public void printA(){        System.out.println("HELLO --> A") ;    }};public class InnerExtDemo01{    public static void main(String args[]){        A x=new X();        x.printA();    }};

这里写图片描述

实现内部接口

abstract class A{   // 定义抽象类    public abstract void printA() ; // 抽象方法    interface B{    // 定义内部接口        public void printB() ;  // 定义抽象方法    }};class X extends A{  // 继承抽象类    public void printA(){        System.out.println("HELLO --> A") ;    }    class Y implements B{   // 定义内部类实现内部接口        public void printB(){            System.out.println("HELLO --> B") ;        }    };};public class InnerExtDemo01{    public static void main(String args[]){        A.B b = new X().new Y() ;        b.printB() ;    }};

这里写图片描述

7-2,接口中包含内部抽象类

不继内部承抽象类

interface A{    // 定义接口    public void printA() ;  // 抽象方法    abstract class B{   // 定义内部抽象类        public abstract void printB() ; // 定义抽象方法    }};class X implements A{   // 实现接口    public void printA(){        System.out.println("HELLO --> A") ;    }};public class InnerExtDemo02{    public static void main(String args[]){        A a=new X();        a.printA();    }};

继承内部抽象类

interface A{    // 定义接口    public void printA() ;  // 抽象方法    abstract class B{   // 定义内部抽象类        public abstract void printB() ; // 定义抽象方法    }};class X implements A{   // 实现接口    public void printA(){        System.out.println("HELLO --> A") ;    }    class Y extends B{  // 继承抽象类        public void printB(){            System.out.println("HELLO --> B") ;        }    };};public class InnerExtDemo02{    public static void main(String args[]){        A.B b = new X().new Y() ;        b.printB() ;    }};

这里写图片描述

8,接口与抽象类的关系

这里写图片描述

这里写图片描述

总结:

在开发中,一个类永远不要去继承一个已经实现好的类,要么继承抽象类,要么实现接口,如果抽象类和接口可以同时使用的话,优先使用接口,可以避免单继承的局限。

1 0