(1)子类可以实现父类的抽象方法,但是不能覆盖父类的非抽象方法;

(2)子类可以增加自己特有的方法;

(3)当子类覆盖或实现父类的抽象方法时,方法的前置条件(即方法的形参)要比父类方法的输入参数更宽松;方法的后置条件(即方法的返回值)要比父类更严格。

(4)如果子类不能完整地实现父类的方法,或者父类的一些方法在子类中已经发生畸形,则建议断开继承关系,采用依赖,聚合,组合等关系继承。

4、代码实例


package designMode.advance.principle;

public class Liskov {

    public static void main(String[] args) {

        A a = new A();

        System.out.println("11-3=" + a.func1(11, 3));

        System.out.println("1-8=" + a.func1(1, 8));

        System.out.println("-----------------------");

        B b = new B();

        //因为B类不再继承A类,因此调用者,不会再func1是求减法

        //调用完成的功能就会很明确

        System.out.println("11+3=" + b.func1(11, 3));//这里本意是求出11+3

        System.out.println("1+8=" + b.func1(1, 8));// 1+8

        System.out.println("11+3+9=" + b.func2(11, 3));

        //使用组合仍然可以使用到A类相关方法

        System.out.println("11-3=" + b.func3(11, 3));// 这里本意是求出11-3

    }

}

//创建一个更加基础的基类

class Base {

    //把更加基础的方法和成员写到Base类

}

// A类

class A extends Base {

    // 返回两个数的差

    public int func1(int num1, int num2) {

        return num1 - num2;

    }

}

// B类继承了A

// 增加了一个新功能:完成两个数相加,然后和9求和

class B extends Base {

    //如果B需要使用A类的方法,使用组合关系

    private A a = new A();

    //这里,重写了A类的方法, 可能是无意识

    public int func1(int a, int b) {

        return a + b;

    }

    public int func2(int a, int b) {

        return func1(a, b) + 9;

    }

    //我们仍然想使用A的方法

    public int func3(int a, int b) {

        return this.a.func1(a, b);

    }

} 

单一职责,Java面试核心知识点精讲

五、开闭原则


1、目的

提高扩展性、便于维护

2、定义

对扩展开放(对提供方),对修改关闭(对使用方)。

当软件需要变化时,尽量通过扩展软件实体的行为来实现变化,而不是通过修改已有的代码来实现。

开闭原则是面向对象设计中最基础的设计原则,它指导我们如何建立稳定灵活的系统,开闭原则只定义了对修改关闭,对扩展开放。

因为抽象灵活性好,适应性广,只要抽象的合理,可以基本保证架构的稳定。而软件中易变的细节,我们用从抽象派生的实现类来进行扩展,当软件需要发生变化时,我们只需要根据需求重新派生一个实现类来扩展就可以了,当然前提是抽象要合理,要对需求的变更有前瞻性和预见性。

六、迪米特法则


1、目的

降低类与类之间的耦合度

2、定义

迪米特法则又叫最少知道原则,即一个类对自己依赖的类知道的越少越好,对于依赖的类不管有多复杂,都尽量将逻辑封装在类的内部,对外除了提供public方法,不泄漏任何信息。

更简单的说法:只与直接朋友通信。

直接朋友:每个对象都会与其它对象有耦合关系,耦合的方式有很多,依赖、关联、组合、聚合等。我们称出现在成员变量,方法参数,方法返回值中的类称为直接朋友,而出现在局部变量中的类不能称为直接朋友,也就是说,陌生的类不要以局部变量的形式出现在类的内部。

3、注意事项和细节

(1)在类的结构设计上,尽量降低类成员的访问权限;

(2)在类的设计上,优先考虑将一个类设计成不变类;

(3)在类的引用上,将引起其他类的次数降到最低;

(4)不暴露类的属性成员,而应该提供相应的访问器(getter、setter);

(5)谨慎使用序列化(serializable)功能;

过分的使用迪米特原则,会产生大量这样的中介和传递类,类之间需要通信就通过第三方转发的方式,就会造成系统的不同模块之间的通信效率降低、使系统的不同模块之间不容易协调等缺点,同时大大增加了系统的复杂度。所以在釆用迪米特法则时需要反复权衡,确保高内聚和低耦合的同时,保证系统的结构清晰。

4、代码实例

下面代码违反了迪米特法则,我平时就这么写的。。。


package designMode.advance.principle;

import java.util.ArrayList;

import java.util.List;

public class Demeter {

    public static void main(String[] args) {

        //创建了一个 SchoolManager 对象

        SchoolManager schoolManager = new SchoolManager();

        //输出学院的员工id 和  学校总部的员工信息

        schoolManager.printAllEmployee(new CollegeManager());

    }

}

//学校总部员工类

class Employee {

    private String id;

    public void setId(String id) {

        this.id = id;

    }

    public String getId() {

        return id;

    }

}

//学院的员工类

class CollegeEmployee {

    private String id;

    public void setId(String id) {

        this.id = id;

    }

    public String getId() {

        return id;

    }

}

//管理学院员工的管理类

class CollegeManager {

    //返回学院的所有员工

    public List<CollegeEmployee> getAllEmployee() {

        List<CollegeEmployee> list = new ArrayList<CollegeEmployee>();

        for (int i = 0; i < 10; i++) { //这里我们增加了10个员工到 list

            CollegeEmployee emp = new CollegeEmployee();

            emp.setId("学院员工id= " + i);

            list.add(emp);

        }

        return list;

    }

}

//学校管理类

//分析 SchoolManager 类的直接朋友类有哪些 Employee、CollegeManager

//CollegeEmployee 不是 直接朋友 而是一个陌生类,这样违背了 迪米特法则

class SchoolManager {

    //返回学校总部的员工

    public List<Employee> getAllEmployee() {

        List<Employee> list = new ArrayList<Employee>();

        for (int i = 0; i < 5; i++) { //这里我们增加了5个员工到 list

            Employee emp = new Employee();

            emp.setId("学校总部员工id= " + i);

            list.add(emp);

        }

        return list;

    }

    //该方法完成输出学校总部和学院员工信息(id)

    void printAllEmployee(CollegeManager sub) {

        //分析问题

        //1. 这里的 CollegeEmployee 不是  SchoolManager的直接朋友

        //2. CollegeEmployee 是以局部变量方式出现在 SchoolManager

        //3. 违反了 迪米特法则

        //获取到学院员工

        List<CollegeEmployee> list1 = sub.getAllEmployee();

        System.out.println("------------学院员工------------");

        for (CollegeEmployee e : list1) {

            System.out.println(e.getId());

        }

        //获取到学校总部员工

        List<Employee> list2 = this.getAllEmployee();

        System.out.println("------------学校总部员工------------");

        for (Employee e : list2) {

            System.out.println(e.getId());

        }

    }

} 

使用迪米特法则改进:


//该方法完成输出学校总部和学院员工信息(id)

void printAllEmployee(CollegeManager sub) {

    //分析问题

    //1. 将输出学院的员工方法,封装到CollegeManager

    sub.printEmployee();

    //获取到学校总部员工

    List<Employee> list2 = this.getAllEmployee();

    System.out.println("------------学校总部员工------------");

    for (Employee e : list2) {

        System.out.println(e.getId());

    }

}

//管理学院员工的管理类

class CollegeManager2 {

//返回学院的所有员工

public List<CollegeEmployee> getAllEmployee() {

    List<CollegeEmployee> list = new ArrayList<CollegeEmployee>();

    for (int i = 0; i < 10; i++) { //这里我们增加了10个员工到 list

        CollegeEmployee emp = new CollegeEmployee();

        emp.setId("学院员工id= " + i);

        list.add(emp);

    }

    return list;

}

//输出学院员工的信息

public void printEmployee() {

    //获取到学院员工

    List<CollegeEmployee> list1 = getAllEmployee();

    System.out.println("------------学院员工------------");

    for (CollegeEmployee e : list1) {

        System.out.println(e.getId());

    }

}

}



简单来说,就是将获取学院员工的方法写到学校员工类中。

![](https://s2.51cto.com/images/20210828/1630163934684375.jpg)

--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

七、合成复用原则

--------

### 1、目的

防止类的体系庞大

### 2、定义

它要求在软件复用时,要尽量先使用组合或者聚合等关联关系来实现,其次才考虑使用继承关系来实现。  

### 最后

**为什么我不完全主张自学?
①**平台上的大牛基本上都有很多年的工作经验了,你有没有想过之前行业的门槛是什么样的,现在行业门槛是什么样的?以前企业对于程序员能力要求没有这么高,甚至十多年前你只要会写个“Hello World”,你都可以入门这个行业,所以以前要入门是完全可以入门的。
②现在也有一些优秀的年轻大牛,他们或许也是自学成才,但是他们一定是具备优秀的学习能力,优秀的自我管理能力(时间管理,静心坚持等方面)以及善于发现问题并总结问题。
如果说你认为你的目标十分明确,能做到第②点所说的几个点,以目前的市场来看,你才真正的适合去自学。

除此之外,对于绝大部分人来说,报班一定是最好的一种快速成长的方式。但是有个问题,现在市场上的培训机构质量参差不齐,如果你没有找准一个好的培训班,完全是浪费精力,时间以及金钱,这个需要自己去甄别选择。

我个人建议线上比线下的性价比更高,线下培训价格基本上没2W是下不来的,线上教育现在比较成熟了,此次疫情期间,学生基本上都感受过线上的学习模式。相比线下而言,线上的优势以我的了解主要是以下几个方面:
①价格:线上的价格基本上是线下的一半;
②老师:相对而言线上教育的师资力量比线下更强大也更加丰富,资源更好协调;
③时间:学习时间相对而言更自由,不用裸辞学习,适合边学边工作,降低生活压力;
④课程:从课程内容来说,确实要比线下讲的更加深入。

**应该学哪些技术才能达到企业的要求?(下图总结)**

**[Java全套资料免费领取方式:戳这里](https://gitee.com/vip204888/java-p7)**

![](https://s2.51cto.com/images/20210828/1630163934635927.jpg)

![](https://s2.51cto.com/images/20210828/1630163935459112.jpg)