zoukankan      html  css  js  c++  java
  • 抽象类和接口

    1. 抽象类

    抽象类中不能有private abstract,为什么?子类没有方法对它进行合理的定义

    // interfaces/AbstractAccess.java
    abstract class AbstractAccess {
        private void m1() {}
    
        // private abstract void m1a(); // illegal
    
        protected void m2() {}
    
        protected abstract void m2a();
    
        void m3() {}
    
        abstract void m3a();
    
        public void m4() {}
    
        public abstract void m4a();
    }

    创建抽象类和抽象方法是有帮助的,因为它们使得类的抽象性很明确,并能告知用户和编译器使用意图。抽象类同时也是一种有用的重构工具,使用它们使得我们很容易地将沿着继承层级结构上移公共方法。

    2. 接口

    Java 8 中接口稍微有些变化,因为 Java 8 允许接口包含默认方法和静态方法——基于某些重要原因,看到后面你会理解。接口的基本概念仍然没变,介于类型之上、实现之下。接口与抽象类最明显的区别可能就是使用上的惯用方式。接口的典型使用是代表一个类的类型或一个形容词,如 Runnable 或 Serializable,而抽象类通常是类层次结构的一部分或一件事物的类型,如 String 或 ActionHero。

    接口同样可以包含属性,这些属性被隐式指明为 static 和 final。

    // interfaces/ImplementingAnInterface.java
    interface Concept { // Package access
        void idea1();
        void idea2();
    }
    
    class Implementation implements Concept {
        @Override
        public void idea1() {
            System.out.println("idea1");
        }
    
        @Override
        public void idea2() {
            System.out.println("idea2");
        }
    }

    3. 默认方法default

    之前我对它只在switch中有接触,其实在jdk-8后,已经可以在接口中加方法的实现了。比如这个default

    // interfaces/InterfaceWithDefault.java
    interface InterfaceWithDefault {
        void firstMethod();
        void secondMethod();
    
        default void newMethod() {
            System.out.println("newMethod");
        }
    }
    // interfaces/Implementation2.java
    public class Implementation2 implements InterfaceWithDefault {
        @Override
        public void firstMethod() {
            System.out.println("firstMethod");
        }
    
        @Override
        public void secondMethod() {
            System.out.println("secondMethod")
        }
    
        public static void main(String[] args) {
            InterfaceWithDefault i = new Implementation2();
            i.firstMethod();
            i.secondMethod();
            i.newMethod();
        }
    }
    firstMethod
    secondMethod
    newMethod

    4. 多继承,这里指的是多实现实现多继承,举几个特殊的例子

    package Test;
    
    // interface/MICollision.java
    import java.util.*;
    
    interface Bob1 {
        default void bob() {
            System.out.println("Bob1::bob");
        }
    }
    
    interface Bob2 {
        default void bob() {
            System.out.println("Bob2::bob");
        }
    }
    class Bobs implements Bob1, Bob2{
        @Override
        public void bob() {
            Bob2.super.bob();
        }
    }
    
    // class Bob implements Bob1, Bob2 {}
    /* Produces:
    error: class Bob inherits unrelated defaults
    for bob() from types Bob1 and Bob2
    class Bob implements Bob1, Bob2 {}
    ^
    1 error
    */
    
    interface Sam1 {
        default void sam() {
            System.out.println("Sam1::sam");
        }
    }
    
    interface Sam2 {
        default void sam(int i) {
            System.out.println(i * 2);
        }
    }
    // This works because the argument lists are distinct:
    class Sam implements Sam1, Sam2 {}
    
    interface Max1 {
        default void max() {
            System.out.println("Max1::max");
        }
    }
    
    interface Max2 {
        default int max() {
            return 47;
        }
    }
    // class Max implements Max1, Max2 {} /* Produces: error: types Max2 and Max1 are imcompatible;
    both define max(), but with unrelated return types class Max implements Max1, Max2 {} ^ 1 error */

    其中第一个的解决方法已经列出,这种调用我也是第一次见,为什么可以直接掉,原因估计还是类已经加载完毕在实际运行到的时候

    5. 接口中的静态方法,要静态,不能实例化的东西必须要让它在加载时搞好。

    // onjava/Operations.java
    package onjava;
    import java.util.*;
    
    public interface Operations {
        void execute();
    
        static void runOps(Operations... ops) {
            for (Operations op: ops) {
                op.execute();
            }
        }
    
        static void show(String msg) {
            System.out.println(msg);
        }
    }

    这里的runOps就像一个模板方法一样,其实现还要看下面。

    // interface/Machine.java
    import java.util.*;
    import onjava.Operations;
    
    class Bing implements Operations {
        @Override
        public void execute() {
            Operations.show("Bing");
        }
    }
    
    class Crack implements Operations {
        @Override
        public void execute() {
            Operations.show("Crack");
        }
    }
    
    class Twist implements Operations {
        @Override
        public void execute() {
            Operations.show("Twist");
        }
    }
    
    public class Machine {
        public static void main(String[] args) {
            Operations.runOps(
                new Bing(), new Crack(), new Twist());
        }
    }

    这里因为在main中进行set值得时候就已经确保了这个类都是接口得实现方式,所以不用担心类是否实现。后面为什么会去走实现类中得方法,这就是一个典型得多态运用。

    Bing
    Crack
    Twist

     对于抽象类中的构造器,实际是不是实例化抽象类,而是当子类的方法全覆盖抽象类后用抽象类的构造来实例化子类。

    6. 完全解耦

    // interfaces/interfaceprocessor/Processor.java
    package interfaces.interfaceprocessor;
    
    public interface Processor {
        default String name() {
            return getClass().getSimpleName();
        }
    
        Object process(Object input);
    }
    
    // interfaces/interfaceprocessor/Applicator.java
    package interfaces.interfaceprocessor;
    
    public class Applicator {
        public static void apply(Processor p, Object s) {
            System.out.println("Using Processor " + p.name());
            System.out.println(p.process(s));
        }
    }
    // interfaces/interfaceprocessor/StringProcessor.java
    // {java interfaces.interfaceprocessor.StringProcessor}
    package interfaces.interfaceprocessor;
    import java.util.*;
    
    interface StringProcessor extends Processor {
        @Override
        String process(Object input); // [1]
        String S = "If she weighs the same as a duck, she's made of wood"; // [2]
    
        static void main(String[] args) { // [3]
            Applicator.apply(new Upcase(), S);
            Applicator.apply(new Downcase(), S);
            Applicator.apply(new Splitter(), S);
        }
    }
    
    class Upcase implements StringProcessor {
        // 返回协变类型
        @Override
        public String process(Object input) {
            return ((String) input).toUpperCase();
        }
    }
    
    class Downcase implements StringProcessor {
        @Override
        public String process(Object input) {
            return ((String) input).toLowerCase();
        }
    }
    
    class Splitter implements StringProcessor {
        @Override
        public String process(Object input) {
            return Arrays.toString(((String) input).split(" "));
        }
    }
    Using Processor Upcase
    IF SHE WEIGHS THE SAME AS A DUCK, SHE'S MADE OF WOOD
    Using Processor Downcase
    if she weighs the same as a duck, she's made of wood
    Using Processor Splitter
    [If, she, weighs, the, same, as, a, duck,, she's, made, of, wood]

    如果用继承也可以完成这项工作,但是继承就意味着和上层类绑定了。

    7. 接口也可以继承接口,这点还经常在重构用

    // interfaces/HorrorShow.java
    // Extending an interface with inheritance
    interface Monster {
        void menace();
    }
    
    interface DangerousMonster extends Monster {
        void destroy();
    }
    
    interface Lethal {
        void kill();
    }
    
    class DragonZilla implements DangerousMonster {
        @Override
        public void menace() {}
    
        @Override
        public void destroy() {}
    }
    
    interface Vampire extends DangerousMonster, Lethal {
        void drinkBlood();
    }
    
    class VeryBadVampire implements Vampire {
        @Override
        public void menace() {}
    
        @Override
        public void destroy() {}
    
        @Override
        public void kill() {}
    
        @Override
        public void drinkBlood() {}
    }
    
    public class HorrorShow {
        static void u(Monster b) {
            b.menace();
        }
    
        static void v(DangerousMonster d) {
            d.menace();
            d.destroy();
        }
    
        static void w(Lethal l) {
            l.kill();
        }
    
        public static void main(String[] args) {
            DangerousMonster barney = new DragonZilla();
            u(barney);
            v(barney);
            Vampire vlad = new VeryBadVampire();
            u(vlad);
            v(vlad);
            w(vlad);
        }
    }

    当打算组合接口时,在不同的接口中使用相同的方法名通常会造成代码可读性的混乱,尽量避免这种情况。

    8. 常量接口,禁止这么用,要用enum

    9. 接口嵌套,这个可以用,但是很少这么用吧。而且对于private和public的控制也较麻烦,我感觉这符合面向对象,但是是不实用的。

    10. 接口和工厂模式

    // interfaces/Factories.java
    interface Service {
        void method1();
        void method2();
    }
    
    interface ServiceFactory {
        Service getService();
    }
    
    class Service1 implements Service {
        Service1() {} // Package access
    
        @Override
        public void method1() {
            System.out.println("Service1 method1");
        }
    
        @Override
        public void method2() {
            System.out.println("Service1 method2");
        }
    }
    
    class Service1Factory implements ServiceFactory {
        @Override
        public Service getService() {
            return new Service1();
        }
    }
    
    class Service2 implements Service {
        Service2() {} // Package access
    
        @Override
        public void method1() {
            System.out.println("Service2 method1");
        }
    
        @Override
        public void method2() {
            System.out.println("Service2 method2");
        }
    }
    
    class Service2Factory implements ServiceFactory {
        @Override
        public Service getService() {
            return new Service2();
        }
    }
    
    public class Factories {
        public static void serviceConsumer(ServiceFactory fact) {
            Service s = fact.getService();
            s.method1();
            s.method2();
        }
    
        public static void main(String[] args) {
            serviceConsumer(new Service1Factory());
            // Services are completely interchangeable:
            serviceConsumer(new Service2Factory());
        }
    }

    工厂模式就是不直接通过new 来调用构造函数,其实本质上也是调用了,否则怎么创建呢。所谓设计模式就是将白话包装成文学作品,这个包装需要很厉害的功底和大量的编程经验,我现在对设计模式也是仅仅停留在会写不会用的程度。

    认为接口是好的选择,从而使用接口不用具体类,这具有诱惑性。几乎任何时候,创建类都可以替代为创建一个接口和工厂。

    很多人都掉进了这个陷阱,只要有可能就创建接口和工厂。这种逻辑看起来像是可能会使用不同的实现,所以总是添加这种抽象性。这变成了一种过早的设计优化。

    任何抽象性都应该是由真正的需求驱动的。当有必要时才应该使用接口进行重构,而不是到处添加额外的间接层,从而带来额外的复杂性。这种复杂性非常显著,如果你让某人去处理这种复杂性,只是因为你意识到“以防万一”而添加新接口,而没有其他具有说服力的原因——好吧,如果我碰上了这种设计,就会质疑此人所作的所有其他设计了。

    恰当的原则是优先使用类而不是接口。从类开始,如果使用接口的必要性变得很明确,那么就重构。接口是一个伟大的工具,但它们容易被滥用。

    一个没有高级趣味的人。 email:hushui502@gmail.com
  • 相关阅读:
    Python Post四种请求方式
    Python 字符串转Base64编解码
    JS 数组遍历
    FineUI MVC 前端获取表格Json通过Post传递后台
    C# Json转DataTable
    MSSQL 关联更新
    Python selenium Message: session not created: This version of ChromeDriver only supports Chrome version 76
    FineUI MVC 同级新增页签
    Tomcat Tomcat的中文乱码设置
    zabbix-4.0-监控服务器的ping告警设置
  • 原文地址:https://www.cnblogs.com/CherryTab/p/11938344.html
Copyright © 2011-2022 走看看