[ Java ] 一文搞懂设计模式常用的七大原则


一、单一职责原则

  • 降低类的复杂性,即一个类应该只负责一项职责。
  • 提高类的可读性,可维护性
  • 降低变更引起的风险
  • 代码逻辑比较简单的情况下,可以在方法级别保持单一职责原则
  • 代码示例
/**
* 完全符合单一职责原则
*/
public class Test {
    public static void main(String[] args) {
        Vehicle vehicle = new Vehicle();
        vehicle.run("汽车");

        Vehicle1 vehicle1 = new Vehicle1();
        vehicle1.run("飞机");
    }
}
class Vehicle{
    public void run(String vehicle){
        System.out.println(vehicle+":在地上跑!");
    }
}
class Vehicle1{
    public void run(String vehicle){
        System.out.println(vehicle+":在天上飞!");
    }
}
/**
* 方法级别的单一职责原则
*/
public class Test {
    public static void main(String[] args) {
        Vehicle vehicle = new Vehicle();
        vehicle.run("汽车");

        vehicle.runAir("飞机");
    }
}
class Vehicle{
    public void run(String vehicle){
        System.out.println(vehicle+":在地上跑!");
    }
    public void runAir(String vehicle){
        System.out.println(vehicle+":在天上飞!");
    }
}

二、接口隔离原则

  • 不应该依赖它不需要的接口,即一个类对另一个类的依赖应该建立在最小接口上

  • 代码示例

/**
 * 违反接口隔离原则,代码示例
 */
interface interface1{
    public void operation1();
    public void operation2();
    public void operation3();
}
class B implements interface1{

    public void operation1() {
        System.out.println("B 实现了 operation1");
    }

    public void operation2() {
        System.out.println("B 实现了 operation2");
    }

    public void operation3() {
        System.out.println("B 实现了 operation3");
    }
}
class D implements interface1{

    public void operation1() {
        System.out.println("D 实现了 operation1");
    }

    public void operation2() {
        System.out.println("D 实现了 operation2");
    }

    public void operation3() {
        System.out.println("D 实现了 operation3");
    }
}

/**
 * A 类 通过接口 interface1 依赖(使用)B 类,但是只用到 1,2 方法
 */
class A{
    public void depend1(interface1 i){
        i.operation1();
    }
    public void depend2(interface1 i){
        i.operation2();
    }
}
/**
 * C 类 通过接口 interface1 依赖(使用)D 类,但是只用到 1,3方法
 */
class C{
    public void depend1(interface1 i){
        i.operation1();
    }
    public void depend3(interface1 i){
        i.operation3();
    }
}
/**
 * 遵循接口隔离原则,代码示例
 */
public class Test {
    public static void main(String[] args) {
        A a = new A();
        a.depend1(new B());
        a.depend2(new B());

        C d = new C();
        interface1 ii = new D();
        d.depend1(new D());
        d.depend3(new D());
    }
}

interface interface1{
    public void operation1();
}
interface interface2{
    public void operation2();
}
interface interface3{
    public void operation3();
}
class B implements interface1,interface2{

    public void operation1() {
        System.out.println("B 实现了 operation1");
    }

    public void operation2() {
        System.out.println("B 实现了 operation2");
    }
}
class D implements interface1,interface3{

    public void operation1() {
        System.out.println("D 实现了 operation1");
    }

    public void operation3() {
        System.out.println("D 实现了 operation3");
    }
}

/**
 * A 类 通过接口 interface1 依赖(使用)B 类,但是只用到 1,2 方法
 */
class A{
    public void depend1(interface1 i){
        i.operation1();
    }
    public void depend2(interface2 i){
        i.operation2();
    }
}
/**
 * C 类 通过接口 interface1 依赖(使用)D 类,但是只用到 1,3方法
 */
class C{
    public void depend1(interface1 i){
        i.operation1();
    }
    public void depend3(interface3 i){
        i.operation3();
    }
}

三、依赖倒转原则

  • 高层模块不应该依赖地层模块,二者都应该依赖其抽象
  • 抽象不应该依赖细节,细节应该依赖抽象
  • 中心思想:面向接口编程
  • 依赖倒转原则是基于这样的设计理念,相对于细节的多变性,抽象的东西要稳定的多。以抽象为基础搭建的架构比以细节为基础的架构要稳定的多。
  • 在java中,抽象指的是接口或抽象类,细节就是具体的实现类
  • 使用接口或抽象类的目的是制定好规范,而不涉及任何具体的操作,把展现细节的任务交给他们的实现类去完成
  • 代码实践
public class Test {
    public static void main(String[] args) {
        Person person = new Person();
        person.receive(new Aemail());
        person.receive(new Awexin());
    }
}
interface Areceiver{
    public String getInfo();
}
class Aemail implements Areceiver{

    @Override
    public String getInfo() {
        return "电子邮件信息:hello world";
    }
}
class Awexin implements Areceiver{

    @Override
    public String getInfo() {
        return "微信信息:hello world";
    }
}
class Person{
    public void receive(Areceiver areceiver){
        System.out.println(areceiver.getInfo());
    }
}

四、里氏替换原则

  • 继承在给程序设计带来便利的同时,也带来了弊端。比如使用继承会给程序带来侵入性,程序的可移植性降低,增加对象间的耦合性,如果一个类被其他的类所继承,则当这个类需要修改时,必须考虑到所有的子类,并且父类修改后,所有涉及到子类的功能都有可能产生故障
  • 在实际编程中,我们常常会通过重写父类的方法完成新的功能,这样写起来虽然简单,但整个继承体系的复用性会比较差。特别是运行多态比较频繁的时候
  • 通用的做法是:原来的父类和子类都继承-一个更通俗的基类,原有的继承关系去掉,
    采用依赖,聚合,组合等关系代替.
  • 使用继承时,遵循里氏替换原则,尽量不要重写父类中的方法
  • 代码实践
/**
 * 不符合里氏替换原则 代码示例
 */
public class Test {
    public static void main(String[] args) {
        A a = new A();
        System.out.println(a.fun1(7, 3)); // 4
        System.out.println(a.fun1(2, 8)); // -6

        B b = new B();
        System.out.println(b.fun1(7, 3)); // 10
        System.out.println(b.fun1(2, 8)); // 10
        System.out.println(b.fun2(2, 8)); // 19
    }
}

class A {
    public int fun1(int a, int b) {
        return a - b;
    }
}

class B extends A {
    @Override
    public int fun1(int a, int b) {
        return a + b;
    }

    public int fun2(int a, int b) {
        return a + b + 9;
    }
}

/**
 * 使用 组合 代替继承(使符合里氏替换原则)
 */
class Base {

}

class A extends Base {
    public int fun1(int a, int b) {
        return a - b;
    }
}

class B extends Base {
    // 使用 组合 代替继承
    private A a = new A();

    public int fun1(int a, int b) {
        return a + b;
    }

    public int fun2(int a, int b) {
        return a + b + 9;
    }

    public int fun3(int a, int b) {
        return this.a.fun1(a, b);
    }
}

五、开闭原则(OCP)

  • 开闭原则(Open Closed Principle)是编程中最基础、最重要的设计原则
  • 一个软件实体如类,模块和函数应该对扩展开放,对修改关闭。用抽象构建框架, .
    用实现扩展细节。
  • 当软件 需要变化时,尽量通过扩展软件实体的行为来实现变化,而不是通过修改已
    有的代码来实现变化。
  • 编程中遵循其它原则,以及使用设计模式的目的就是遵循开闭原则。
  • 代码实践
public class Test {
    public static void main(String[] args) {
        DrawShape draw = new DrawShape();
        draw.drawShape(new Circle());
        draw.drawShape(new Triangle());
    }
}
class DrawShape{
    public void drawShape(Shape shape){
        shape.draw();
    }
}
abstract class Shape{
    public abstract void draw();
}
class Circle extends Shape{

    @Override
    public void draw() {
        System.out.println("绘制圆形");
    }
}
class Triangle extends Shape{

    @Override
    public void draw() {
        System.out.println("绘制三角形");
    }
}

六、迪米特法则

  • 一个对象应该对其他对象保持最少的了解
  • 类与类关系越密切,耦合度越大
  • 迪米特法则,又叫最少知道原则,即一个类对自己依赖的类知道的越少越好。也就是说,对于被依赖的类不管多么复杂,都尽量将逻辑封装在类的内.部。对外除了提供的public方法,不对外泄露任何信息
  • 代码实践
/**
 * 不符合迪米特法则的代码示例
 */
public class Test {
    public static void main(String[] args) {
        SchoolManage schoolManage = new SchoolManage();
        schoolManage.printEmployee(new CollegeManage());
    }
}

class SchoolManage {
    private List<Employee> employeeList;

    SchoolManage() {
        employeeList = new ArrayList<>();
        for (int i = 0; i < 10; i++) {
            employeeList.add(new Employee("学校员工"+i));
        }
    }

    public void printEmployee(CollegeManage collegeManage){
        for(Employee e : this.employeeList){
            System.out.println(e.getName());
        }
        System.out.println("---------------------");
        for(Employee e : collegeManage.getEmployeeList()){
            System.out.println(e.getName());
        }
    }
}

class CollegeManage {
    private List<Employee> employeeList;
    CollegeManage() {
        employeeList = new ArrayList<>();
        for (int i = 0; i < 5; i++) {
            employeeList.add(new Employee("学院员工"+i));
        }
    }

    public List<Employee> getEmployeeList() {
        return employeeList;
    }
}

class Employee {
    private String name;

    public String getName() {
        return name;
    }

    Employee(String name) {
        this.name = name;
    }
}

/**
 * 将上面的代码简单修改一下,使符合迪米特法则
 */
class SchoolManage {
    private List<Employee> employeeList;
    SchoolManage() {
        employeeList = new ArrayList<>();
        for (int i = 0; i < 10; i++) {
            employeeList.add(new Employee("学校员工"+i));
        }
    }
    public void printEmployee(CollegeManage collegeManage){
        for(Employee e : this.employeeList){
            System.out.println(e.getName());
        }
        System.out.println("--------------------");
        collegeManage.printEmployee();
    }
}

class CollegeManage {
    private List<Employee> employeeList;
    CollegeManage() {
        employeeList = new ArrayList<>();
        for (int i = 0; i < 5; i++) {
            employeeList.add(new Employee("学院员工"+i));
        }
    }
    public List<Employee> getEmployeeList() {
        return employeeList;
    }
    public void printEmployee(){
        for(Employee e : this.employeeList){
            System.out.println(e.getName());
        }
    }
}

七、合成复用原则

  • 尽量使用 合成 / 聚合 的方式,而不是使用继承

依赖关系

  • 1、泛化关系:继承关系
class A{
    
}
class B extends A{
   
}

  • 2、实现关系:类实现接口
interface A{

}
class B implements A{

}
  • 3、关联关系
    • 单向一对一关系
    • 双向一对一关系
/**
 * 单向一对一关系
 */
class A{
    private B b;
}
class B implements A{

}
/**
 * 双向一对一关系
 */
class A{
    private B b;
}
class B implements A{
    private A a;
}

  • 4、聚合关系:表示的是整体和部分的关系,整体与部分可以分开。聚合关系是关联关系的特例

  • 5、组合关系:组合关系:也是整体与部分的关系,但是整体与部分不可以分开。

class A{
    public String say(){
        return "我是 A ";
    }
}
class B{
    private A a = new A();
    public void func(){
        System.out.println(this.a.say());
    }
}

设计原则核心思想

  • 找出应用中可能需要变化之处,把它们独立出来,不要和那些不需要变化的代
    码混在一起。
  • 针对接口编程,而不是针对实现编程。
  • 为了交互对象之间的松耦合设计而努力

在这里插入图片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章