接口


接口

  1. 属于抽象的数据类型,也是不能够被实例化的
  2. 接口中不允许定义普通属性的,不允许出现构造的.
  3. jdk8.x允许在接口中使用default关键字来定义普通方法.
  4. 接口也是用来定义抽象的方法的.接口中的方法都是抽象的方法.
  5. 接口的属性都是公开的静态的常量属性.
  6. 定义接口的关键字是interface,编译之后也是.class字节码文件
  7. 接口也是可以静态方法的.

命名规则

使用I开头或者able结尾

多态的另外应用

面向接口编程

  1. 对象的编译时类型写成接口,对象的运行时类型写成是实现类
  2. 方法的参数类型写成接口,调用方法时可以传入这个接口的任意一个实现类.
  3. 方法的返回类型写成接口,方法的返回结果的类型可以是这个接口的任意一个实现类.

接口的规则

  1. 接口和类 - 类是可以去实现这个接口的.

    1. 接口天生是用来是实现类来实现的 - implements
    2. 普通的类去实现某个接口的话,那么必须要实现这个接口中所有的抽象方法
    3. 如果抽象的类去实现某个接口的话,那么可以选择实现或者不实现.
    4. 一个接口可以拥有多个实现类.
    5. 一个类可以同时实现多个接口,接口之间用逗号隔开.需要实现这些接口中所有的抽象方法.
  2. 接口和接口

    1. 一个接口可以继承多个接口,接口是支持多重继承的.

应用

提供了一种”契约机制”,屏蔽了底层的具体的实现,为了程序的拓展

作用 - 制定开发的这个软件中的功能 - “业务方法”

接口的分类

  1. 业务接口 - 该接口中只定义抽象方法

  2. 常量接口 - 该接口中只定义了常量属性,管理系统中所有的常量属性的.jdk5.x使用了枚举类型来替代了常量接口

  3. 标记接口 - 什么都没有,做标记的.

    public interface IA{}
    
    public class Aimpl implements IA{...}
    
    Aimpl a = new Aimpl();
    System.out.println(a instanceof IA);//true
    
  4. 函数式接口 - jdk8.x - 配合jdk8.x - lambda表达式

    里面只有一个抽象方法的接口 - @FunctionalInterface

设计模式概述

设计模式概念

设计模式(Design Pattern)是一套被反复使用、多数人知晓的、经过分类的、代码设计经验的总结

使用设计模式的目的:为了代码可重用性、让代码更容易被他人理解、保证代码可靠性。 设计模式使代码编写真正工程化;设计模式是软件工程的基石脉络,如同大厦的结构一样。

项目中合理地运用设计模式可以完美地解决很多问题,每种模式在现实中都有相应的原理来与之对应,每种模式都描述了一个在我们周围不断重复发生的问题,以及该问题的核心解决方案,这也是设计模式能被广泛应用的原因。

七大原则

为什么要提倡“Design Pattern”呢?根本原因是为了代码复用,增加可维护性。那么怎么才能实现代码复用呢?面开闭原则具有理想主义的色彩,它是面向对象设计的终极目标。其他几条,则可以看做是开闭原则的实现方法。

单一职责原则

简介:单一职责原则(Single Responsiblity Principle SRP)

接口或类只提供一种业务实现。
单一职责原则宗旨是每个接口、类的功能,只能用来做专门的事,强调系统内业务职责唯一,避免职责扩散,做到业务统一管理.

开闭原则

简介:总原则:开闭原则(Open Close Principle)

开闭原则就是说对扩展开放,对修改关闭。在程序需要进行拓展的时候,不能去修改原有的代 码,而是要扩展原有代码,实现一个热插拔的效果。所以一句话概括就是:为了使程序的扩展性好,易于维护和升级。想要达到这样的效果,我们需要使用接口和抽象类等,后面的具体设计中我们会提到这点。 单一职责原则不要存在多于一个导致类变更的原因,也就是说每个类应该实现单一的职责,如若不然,就应该把类拆分。

里氏替换原则

简介:里氏替换原则(Liskov Substitution Principle)

里氏代换原则(Liskov Substitution Principle LSP)面向对象设计的基本原则之一。 里氏代换原则中说,任何基类可以出现的地方,子类一定可以出现。 LSP 是继承复用的基石,只有当衍生类可以替换掉基类,软件单位的功能不受到影响时,基类才能真正被复用,而衍生类也能够在基类的基础上增加新的行为。里氏代换原则是对“开-闭”原则的补充。实现“开-闭”原则的关键步骤就是抽象化。而基类与子类的继承关系就是抽象化的具体实现,所以里氏代换原则是对实 现抽象化的具体步骤的规范。里氏替换原则中,子类对父类的方法尽量不要重写和重载因为父类代表了定义好的结构,通过这个规范的接口与外界交互,子类不应该随便破坏它。

因为继承带来的侵入性,增加了耦合性,也降低了代码灵活性,父类修改代码,子类也会受到影响,此时就需要里氏替换原则。

  • 子类必须实现父类的抽象方法,但不得重写(覆盖)父类的非抽象(已实现)方法。
  • 子类中可以增加自己特有的方法。
  • 当子类覆盖或实现父类的方法时,方法的前置条件(即方法的形参)要比父类方法的输入参数更宽松。
  • 当子类的方法实现父类的抽象方法时,方法的后置条件(即方法的返回值)要比父类更严格。

依赖倒转原则

简介:依赖倒转原则(Dependence Inversion Principle)

这个是开闭原则的基础,具体内容:面向接口编程,依赖于抽象而不依赖于具体。写代码时用到具体类时,不与具体类交互,而与具体类的上层接口交互。

接口隔离原则

简介:接口隔离原则(Interface Segregation Principle

这个原则的意思是:每个接口中不存在实现类用不到却必须实现的方法,如果不然,就要将接口拆分。使用多个隔离的接口,比使用单个接口(多个接口方法集合到一个的接口)要好。

迪米特法则

简介:迪米特法则(最少知道原则)(Demeter Principle)

就是说:一个类对自己依赖的类知道的越少越好。也就是说无论被依赖的类多么复杂,都应该将逻辑封装方法的内部,通过 public 方法提供给外部。这样当被依赖的类变化时,才能最小的影响该类。 最少知道原则的另一个表达方式是:只与直接的朋友通信。类之间只要有耦合关系,就叫朋友关系。耦合分为依赖、关联、聚合、组合等我们称出现为成员变量、方法参数、方法返回值中的类为直接朋友局部变量、临时变量则不是直接的朋友。我们要求陌生的类不要作为局部 变量出现在类中。

合成复用原则

简介:合成复用原则(Composite Reuse Principle)

原则是尽量首先使用合成/聚合的方式,而不是使用继承。

简单工厂模式

简单工厂模式是属于创建型模式但不属于23种GOF设计模式之一。简单工厂模式是由一个工厂对象决定创建出哪一种产品类的实例。简单工厂模式是工厂模式家族中最简单实用的模式,可以理解为是不同工厂模式的一个特殊实现。简单工厂一般分为:普通简单工厂多方法简单工厂静态方法简单工厂

作用:把对象的创建和对象的使用分离

User user = new User();//对象的创建和对象使用没有分离

普通简单工厂 - 必须要脱手写出来的.

//1. 根据传入的参数来返回某个具体的产品[对象]
package tech.aistar.design.factory.simple01;

/**
 * 本类用来演示: 简单工厂
 *
 * @author: success
 * @date: 2021/7/23 3:19 下午
 */
public class ProductFactory {
    public static final int QQ = 1;
    public static final int WX = 2;

    //根据传入的参数来返回某个具体的产品
    //多态的应用 - 面向接口编程
    //3. 方法的返回类型写成接口,方法的执行结果可以是这个接口的任意一个实现类.
    public static Sender getInstance(int type){
        Sender sender = null;

        switch (type){
            case 1:
                //对象的创建 - 复杂的过程...
                sender = new QQSender();
                break;
            case 2:
                sender = new WXSender();
                break;
            default:
                System.out.println("参数不合法");
                break;
        }

        return sender;
    }
}

多方法简单工厂

package tech.aistar.design.factory.simple02;

/**
 * 本类用来演示: 多方法工厂
 *
 * @author: success
 * @date: 2021/7/23 3:32 下午
 */
public class ProductFactory {

    //有几个产品,就定义几个方法
    //每个方法负责生成一个产品
    public Sender createQQ(){
        return new QQSender();
    }

    public Sender createWx(){
        return new WXSender();
    }
}

静态方法简单工厂

package tech.aistar.design.factory.simple02;

/**
 * 本类用来演示: 多方法工厂
 *
 * @author: success
 * @date: 2021/7/23 3:32 下午
 */
public class ProductFactory {

    //有几个产品,就定义几个方法
    //每个方法负责生成一个产品
    public static Sender createQQ(){
        return new QQSender();
    }

    public static Sender createWx(){
        return new WXSender();
    }
}

简单工厂优缺点

优点:

  • 很明显,简单工厂的特点就是“简单粗暴”,通过一个含参的工厂方法,我们可以实例化任何产品类,上至飞机火箭,下至土豆面条,无所不能。所以简单工厂有一个别名:上帝类。

缺点:

  • 任何”东西“的子类都可以被生产,负担太重。当所要生产产品种类非常多时,工厂方法的代码量可能会很庞大

  • 在遵循开闭原则(对拓展开放,对修改关闭)的条件下,简单工厂对于增加新的产品,无能为力。因为增加新产品只能通过修改工厂方法来实现。

工厂方法模式

简单工厂模式有一个问题就是,类的创建依赖工厂类,也就是说,如果想要拓展程序,必须对工厂类进行修改,这违背了开闭原则,所以,从设计角度考虑,有一定的问题,如何解决?就用到工厂方法模式,创建一个工厂接口和创建多个工厂实现类,这样一旦需要增加新的功能, 直接增加新的工厂类就可以了,不需要修改之前的代码

工厂方法模式优缺点

优点:

  • 工厂方法模式就很好的减轻了工厂类的负担,把某一类/某一种东西交由一个工厂生产;(对应简单工厂的缺点1)
  • 同时增加某一类”东西“并不需要修改工厂类,只需要添加生产这类”东西“的工厂即可,使得工厂类符合开闭原则。

缺点:

  • 相比简单工厂,实现略复杂。
  • 对于某些可以形成产品族的情况处理比较复杂(相对抽象工厂)。

抽象工厂模式

抽象工厂模式是所有形态的工厂模式中最为抽象和最具一般性的一种形态。抽象工厂模式是指当有多个抽象角色时,使用的一种工厂模式。抽象工厂模式可以向客户端提供一个接口,使客户端在不必指定产品的具体的情况下,创建多个产品族中的产品对象。根据里氏替换原则,任何接受父类型的地方,都应当能够接受子类型。因此,实际上系统所需要的,仅仅是类型与这些抽象产品角色相同的一些实例,而不是这些抽象产品的实例。换言之,也就是这些抽象产品的具体子类的实例。工厂类负责创建抽象产品的具体子类的实例。

抽象工厂模式优缺点

优点:

  • 抽象工厂模式隔离了具体类的生产,使得客户并不需要知道什么被创建。
  • 当一个产品族中的多个对象被设计成一起工作时,它能保证客户端始终只使用同一个产品族中的对象。
  • 增加新的具体工厂和产品族很方便,无须修改已有系统,符合“开闭原则”。

​ 缺点:

  • 增加新的产品等级结构很复杂,需要修改抽象工厂和所有的具体工厂类。

作业

  1. 循环

  2. OO题

    Book[id,name,price...]
    
    1.定义图书操作业务接口 IBookBiz
    
    有如下方法:
    //添加图书
     void add(Book b);
    //根据图书name 来删除指定图书
     void deleteByName(String name);
    //打印出所有的图书信息
     void outputAllBooks();
    
    2. 定义 数组图书管理业务实现类(ArrayBookBiz) 
    实现 IBookBiz接口,
    实现所有方法,
    提示,给出如下属性
    属性:
    private static final int CAPACITY = 5;
    private int count; //代表有效图书数量
    private Book[] books = new Book[CAPACITY];
    方法:
      就是实现接口中的所有方法
    
    最后,写测试类,测试这三个方法.
    
  3. 接口练习题

    接口更重要的作用:作为模块与模块之间一个协议,软件生产一直希望能够像硬件生产一样:主板可由一个厂家生产,显卡可由另一个厂家生产,用户只需要将显卡插到主板上的显卡插槽上,便可以协同工作了。(插槽——主板、显卡的标准接口已经确定,插槽就是接口)。显卡厂商去实现接口中所暴露出来的方法。主板只需要利用显卡的插槽去获取(调用)显卡的功能。
    1、    定义一个显卡接口VideoCard,此接口中有抽象方法:
        1videoRunning():显示显卡运行信息 ;
        2videoClosing():显示显卡停止工作时的信息;
    2、    定义一个芯片接口Cpu,此接口中有抽象方法:
        1cpuRunning():显示显卡运行信息 ;
        2cpuClosing():显示显卡停止工作时的信息;
    3、    定义类IntelCpu:实现Cpu接口的全部功能,其中包括:
        1)    无参构造方法:显示:” Make an Intel's CPU”.
        2)    实现Cpu接口的所有方法
    4、    定义类DmengVideoCard:实现VideoCard接口的全部功能,其中包括:
        1)    无参构造方法:显示:”Make a Dmeng's VideoCard”.
        2)    实现VideoCard接口的所有方法.
    5、    定义类Mainboard
        1)    创建有参构造体,传入显卡和芯片
        2run():显示主板运行信息
        3close():显示主板停止信息
    6、    定义一个Computer类,包含主函数main(),组装一台电脑,测试接口的应用,其中main()方法包括:
        1)    买一块Dmeng公司的显卡
        2)    买一块Intel公司的芯片
        3)    买一块主板:插上显卡、芯片
        4)    组装好后,开机运行显示显卡、芯片、主板等开机信息。
        5)    关机信息显示
        6)    创建openPC方法,打开电脑。
        7)    创建closePC方法,关闭电脑。
    
  4. 预习题 - static关键字

    1.  
    public class Cygnus{
        static int value = 9;  
    
         private void printValue(){
            int value = 69; 
            System.out.println(this.value);
        }
    
        public static void main(String[] args) throws Exception{
            new Cygnus().printValue();
        }
    

}

这个程序会有下面哪种结果?
A. 编译错误
B. 打印9
C. 打印69
D. 运行时抛出异常


  1. 写出以下程序的输出结果
    class Base{

    static{

     System.out.println("base static");
    

    }

    public Base(){

     System.out.println("base constructor");
    

    }
    }

public class Test extends Base{

   static{
       System.out.println("test static");
   }

   public Test(){
super();
       System.out.println("test constructor");
   }

   public static void main(String[] args) {
       new Test();
   }

}


  1. 写出以下程序的输出结果
    public class Test {

    static{

     System.out.println("test static 1");
    

    }
    public static void main(String[] args) {

    }

    static{

     System.out.println("test static 2");
    

    }
    }

---------------------------------------------------------------------------------------
   
  4. public class test{

   static{
        int x=5;
   }
   static int x,y;
   public static void main(String args[]){
      x--;
      myMethod( );
      System.out.println(x+y+ ++x);
   }
   public static void myMethod( ){
     y=x++ + ++x;
   }

}
A. 编译错误
B. 输出:1
C. 输出:2
D. 输出:3
E. 输出:7
F. 输出:8
—————————————————————————————

  5. 阅读下列程序,选择哪一个是正确的输出结果 

class HelloA{
public HelloA() {
         System.out.println(“I’m A class “);
     }
static{
     System.out.println(“static A”);
}
}

public class HelloB extends HelloA{
    public HelloB(){
        System.out.println(“I’m B class”);
    }
    static{
        System.out.println(“static B”);
    }

   public static void main (String[] args){

         new HelloB();
    }
}

A. static A I’m A class static B I’m B class
B. I’m A class I’m B class static A static B
C. static A static B I’m A class I’m B class
D. I’m A class static A I’m B class static B

---------------------------------------------------------------------------------------
   
  6. 以下代码的输出结果是?

public class B{
public static B t1 = new B();
public static B t2 = new B();

   {
       System.out.println("构造块");
   }

   static{
       System.out.println("静态块");
   }

   public static void main(String[] args){
       B t = new B();
   }

}

A. 静态块 构造块 构造块 构造块
B. 构造块 静态块 构造块 构造块
C. 构造块 构造块 静态块 构造块
D. 构造块 构造块 构造块 静态块
—————————————————————————————

  7. 下面代码在main方法代码后可以正常使用的是( )

public class Test{
private int a=10;
int b=20;
static int c=1;
public static void main(String arg[]){
Test t = new Test();
}
}

A. t.a
B. this.c
C. Test.b
D. Test.c
—————————————————————————————

  8. 下列程序执行后结果为( )

class A {
public int func1(int a, int b) {
return a - b;
}
}
class B extends A {
public int func1(int a, int b) {
return a + b;
}
}

public class ChildClass {
public static void main(String[] args) {
A a = new B();
B b = new B();
System.out.println(“Result=” + a.func1(100, 50));
System.out.println(“Result=” + b.func1(100, 50));
}
}
A. Result=150Result=150
B. Result=100Result=100
C. Result=100Result=150
D. Result=150Result=100
—————————————————————————————

  9. 以下代码执行后输出结果为( )

public class Test{
public static Test t1 = new Test();

   {
        System.out.println("blockA");
   }

   static{
       System.out.println("blockB");
   }

   public static void main(String[] args){
       Test t2 = new Test();
   }
}

A. blockAblockBblockA
B. blockAblockAblockB
C. blockBblockBblockA
D. blockBblockAblockB



文章作者: 码农耕地人
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 码农耕地人 !
  目录