栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

设计模式七大原则

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

设计模式七大原则

目录
  • 设计模式
    • 一、 概念
      • 1.1 设计模式是什么
      • 1.2 设计模式 的目的
    • 二、 设计模式七大原则
      • 2.1 单一职责原则
        • 应用举例
        • 注意事项
      • 2.2 接口隔离原则
        • 应用实例
      • 2.3 依赖倒转原则(Dependence Inversion Principle)
        • 应用举例
        • 依赖关系传递的三种方式
        • 小结
      • 2.4 里氏替换原则
        • IOO中的继承性思考和说明
        • 里氏替换原则概述
        • 应用举例
      • 2.5 开闭原则ocp(Open Closed Principle)
        • 概述
        • 应用举例
      • 2.6 迪米特法则
        • 概述
        • 应用举例
        • 注意事项
      • 2.7 合成复用原则
        • 概述
      • 3 设计原则核心思想

设计模式 一、 概念
1.1 设计模式是什么

设计模式是对软件设计中普遍存在(反复出现)的各种问题所提出的解决方案。

1.2 设计模式 的目的

设计模式是为了让程序(软件)拥有更好的

  1. 代码重用性(即:相同的功能代码,可以不用多次编写)
  2. 可读性(即:相当于代码的规范性,便于其他的程序员阅读和理解)
  3. 可扩展性(即:相当于代码的可维护性,当需要增加新的功能时,非常的方便)
  4. 可靠性(即:增加了新的功能代码,对原有的功能没有影响)
  5. 使程序呈现高内聚,低耦合的特性
二、 设计模式七大原则

设计模式原则就是程序员在编程时应当遵守的原则,也是各种设计模式的基础。(设计模式为什么这样设计的依据)

2.1 单一职责原则

对于类来说,每一个类负责一项职责,如果一个类有两个或以上的职责,如果其中一个职责变更,可能会造成其他的职责发生错误,所以需要将该类的粒度进行分解。

应用举例
 
public class SingleResponsibility1 {
    
    public static void main(String[] args) {
        vehicle vehicle = new vehicle();
        vehicle.run("汽车");
        vehicle.run("飞机");
        vehicle.run("轮船");
    }
}

class vehicle {
    public void run(String vehicle) {
        System.out.println(vehicle + " 在公路上运行");
    }
}

运行结果:

汽车 在公路上运行
飞机 在公路上运行
轮船 在公路上运行

解决方案一:

 
public class SingleResponsibility2 {

    public static void main(String[] args) {
        vehicle vehicle = new vehicle();
        AirVehicle airVehicle = new AirVehicle();
        RoadVehicle roadVehicle = new RoadVehicle();
        SeaVehicle seaVehicle = new SeaVehicle();
        airVehicle.run("汽车,摩托");
        roadVehicle.run("飞机,战斗机");
        seaVehicle.run("舰艇,渔船");
    }
}


class RoadVehicle {
    public void run(String vehicle) {
        System.out.println(vehicle + "在公路上运行。。");
    }
}


class AirVehicle {
    public void run(String vehicle) {
        System.out.println(vehicle + "在空中运行。。");
    }
}


class SeaVehicle {
    public void run(String vehicle) {
        System.out.println(vehicle + "在海上运行。。");
    }
}

解决方案二:

 
public class SingleResponsibility3 {

    public static void main(String[] args) {
        Vehicle1 vehicle1 = new Vehicle1();
        vehicle1.roadRun("汽车");
        vehicle1.airRun("飞机");
        vehicle1.seaRun("轮船");
    }
}


class Vehicle1 {
    public void roadRun(String vehicle) {
        System.out.println(vehicle + "在公路上运行。。");
    }

    public void airRun(String vehicle) {
        System.out.println(vehicle + "在空中上运行。。");
    }

    public void seaRun(String vehicle) {
        System.out.println(vehicle + "在海上运行。。");
    }
}
注意事项
  1. 降低类的复杂度,一个类只负责单一的职责
  2. 提高类的可读性,可维护性。
  3. 降低变更带来的风险
  4. 通常情况,应当严格遵守单一职责原则,只有逻辑足够简单,才可以在代码级别上违反单一职责原则;只有类中的方法足够少,可以在方法级别上保证单一职责原则。
2.2 接口隔离原则

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

应用实例
  • 接口Interface1中有5个方法。类B与类D实现该接口。
  • 类A与类C分别依赖与类B与类D实现方法。

分析:

  • 类A依赖与类B其中的1,2,3号方法,由于类B实现了接口Interface1中所有的方法,那么类B的其他4,5号方法没能被依赖实现。
  • 类C依赖于类D中的1,4,5号方法,由于类D实现了接口Interface1中的所有方法,那么类D的其他2,3号方法没能被依赖实现。
  • 这种接口的实现方法就没能实现接口隔离原则

代码实现:

public class InterfaceSegregation1 {
    public static void main(String[] args) {
        A a = new A();
        B b = new B();
        C c = new C();
        D d = new D();

        // 类A依赖类B实现B的方法
        a.depend1(b);
        a.depend2(b);
        a.depend3(b);

        // 类C依赖类D实现D的方法
        c.depend1(d);
        c.depend4(d);
        c.depend5(d);
    }
}

// 接口1
interface Interface1 {

    void operation1();

    void operation2();

    void operation3();

    void operation4();

    void operation5();
}

class B implements Interface1 {

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

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

    @Override
    public void operation3() {
        System.out.println("B 实现了方法operation3");
    }

    @Override
    public void operation4() {
        System.out.println("B 实现了方法operation4");
    }

    @Override
    public void operation5() {
        System.out.println("B 实现了方法operation5");
    }
}

class D implements Interface1 {

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

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

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

    @Override
    public void operation4() {
        System.out.println("D 实现了方法operation4");
    }

    @Override
    public void operation5() {
        System.out.println("D 实现了方法operation5");
    }
}

class A {

    public void depend1(Interface1 i) {
        i.operation1();
    }

    public void depend2(Interface1 i) {
        i.operation2();
    }

    public void depend3(Interface1 i) {
        i.operation3();
    }
}

class C {

    public void depend1(Interface1 i) {
        i.operation1();
    }

    public void depend4(Interface1 i) {
        i.operation4();
    }

    public void depend5(Interface1 i) {
        i.operation5();
    }
}

改进: 防止类A与类C实现不需要的方法

  • 将原有的接口Interface1拆分成几个独立的接口,类A与类C分别于他们需要的接口简历依赖的关系,也就是采用了接口隔离原则。
  • 这里将原来的Interface1拆分成三个接口。

    代码实现:
public class InterfaceSegregation2 {
    public static void main(String[] args) {
        A a = new A();
        B b = new B();
        C c = new C();
        D d = new D();
        // 类A依赖类B实现B的方法
        a.depend1(b);
        a.depend2(b);
        a.depend3(b);

        // 类C依赖类D实现D的方法
        c.depend1(d);
        c.depend4(d);
        c.depend5(d);
    }
}

// 接口1
interface Interface1{

    void operation1();
}

// 接口2
interface Interface2{

    void operation2();

    void operation3();
}

// 接口3
interface Interface3{

    void operation4();

    void operation5();
}

class B implements Interface1,Interface2{

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

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

    @Override
    public void operation3() {
        System.out.println("B 实现了方法operation3");
    }
}

class D implements Interface1,Interface3{

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

    @Override
    public void operation4() {
        System.out.println("D 实现了方法operation4");
    }

    @Override
    public void operation5() {
        System.out.println("D 实现了方法operation5");
    }
}

class A {
    public void depend1(Interface1 i) {
        i.operation1();
    }

    public void depend2(Interface2 i) {
        i.operation2();
    }

    public void depend3(Interface2 i) {
        i.operation3();
    }
}

class C {
    public void depend1(Interface1 i) {
        i.operation1();
    }

    public void depend4(Interface3 i) {
        i.operation4();
    }

    public void depend5(Interface3 i) {
        i.operation5();
    }
}
2.3 依赖倒转原则(Dependence Inversion Principle)
  1. 高层模块不应该依赖底层模块,两者都应该依赖其抽象。
  2. 抽象不应该依赖细节,细节应该依赖抽象。
  3. 依赖倒转(倒置)的中心思想是面向接口编程。
  4. 依赖倒转原则是基于这样的设计理念,相对于细节的多变性,抽象的东西要稳定得多。以抽象为基础搭建的架构比以细节为基础的架构要稳定的多。在java中,抽象指的是接口或抽象类,细节就是具体的实现类。
  5. 使用接口或抽象类的目的是指定好规范,而不涉及任何具体的操作,把展现细节的任务交给他们的实现类去完成。
应用举例

这里以球员Kobe为例,被教练安排比赛位置。

 
public class DependenceInversion1 {
    public static void main(String[] args) {
        Kobe kobe = new Kobe();
        kobe.commanded(new PG());
    }
}

class Kobe {
    void commanded(PG pg) {
        System.out.println("被命令" + pg.play());
    }
}

class PG {
    String play() {
        return "去打控球后卫!";
    }
}

class SG{
    String play(){
        return "去打得分后卫!";
    }
}

代码改进:

public class DependenceInversion2 {

    public static void main(String[] args) {

        Kobe kobe = new Kobe();
        kobe.commanded(new PG());
        kobe.commanded(new SG());

    }
}

interface Position {

    String play();
}

class PG implements Position {

    @Override
    public String play() {
        return "去打组织后卫!";
    }
}

class SG implements Position {

    @Override
    public String play() {
        return "去打得分后卫!";
    }
}

class Kobe {

    void commanded(Position s) {
        System.out.println("被命令" + s.play());
    }
}
依赖关系传递的三种方式
  1. 接口传递:如上的改进方式使用的就是接口传递。
  2. 构造方法传递
  3. setter方式传递

代码实例:

public class DependencyPass {

    public static void main(String[] args) {
        
        // 接口传递
        Kobe kobe = new Kobe();
        kobe.commanded(new SG());
        
        // 构造方法传递
//        kobe kobe = new kobe(new SG());
//        kobe.commanded();
//
//        // setter方式传递
//        Lin lin = new Lin();
//        lin.setPosition(new PG());
//        lin.commanded();

    }
}

interface Position {

    String play();
}

class PG implements Position {

    @Override
    public String play() {
        return "去打组织后卫!";
    }
}

class SG implements Position {

    @Override
    public String play() {
        return "去打得分后卫!";
    }
}





interface Player {
    void commanded(Position pos);
}

class Kobe implements Player {

    @Override
    public void commanded(Position pos) {
        System.out.println("被命令" + pos.play());
    }
}




//class kobe {
//
//    private Position pos;
//
//    kobe(Position pos) {
//        this.pos = pos;
//    }
//
//    void commanded() {
//        System.out.println("被命令" + this.pos.play());
//    }
//}







//interface Player {
//
//    void commanded();
//
//    void setPosition(Position pos);
//}
//
//class Lin implements Player {
//
//    private Position pos;
//
//    @Override
//    public void commanded() {
//        System.out.println("被命令" + this.pos.play());
//    }
//
//    @Override
//    public void setPosition(Position pos) {
//        this.pos = pos;
//    }
//}
小结
  1. 底层模块尽量都要有抽象类或接口,或两者都有,程序的稳定性会更加好。
  2. 变量的声明类型尽量是抽象类或接口,这样我们的变量引用和实际对象间就存在一个缓冲层,利于程序扩展和优化。
  3. 继承时遵循里氏替换原则。
2.4 里氏替换原则
IOO中的继承性思考和说明
  1. 继承包含这样的一句定义:父类中凡是已经实现好的方法,实际上是在设定规范和契约,虽然他不强制要求所有的子类必须遵循这些契约,但是如果子类对这些已经实现的方法任意修改,就会对整个集成体系造成破坏。
  2. 继承在给程序设计带来便利的同时,也带来了弊端。比如使用继承会给程序带来侵入性,程序的可移植性降低,增加对象间的耦合性,如果一个类被其他的类所继承,则当该类需要修改时,并且子类修改后,所有涉及到子类的功能都有可能产生故障。
里氏替换原则概述
  1. 所有引用基类的地方必须能透明地使用其子类的对象。(即尽可能地不要重写基类的方法,保持基类和子类中的方法统一—透明)。
  2. 在使用继承时,遵循里氏替换原则,在子类中尽量不要重写父类的方法。
  3. 里氏替换原则说明:继承实际上让两个类耦合性增加,在适当的情况下,可以通过聚合,组合,依赖来解决问题。
应用举例
 
public class LiskovSubstitution1 {

    public static void main(String[] args) {
        A a = new A();
        System.out.println("10-5=" + a.fun1(10, 5));

        B b = new B();
        System.out.println("10-5=" + b.fun1(10, 5));
        System.out.println("10+5+9=" + b.fun2(10, 5));
    }
}

class A {

    Integer fun1(int a, int b) {
        return a - b;
    }
}

class B extends A {

    @Override
    Integer fun1(int a, int b) {
        return a + b;
    }
    
    Integer fun2(int a, int b) {
        return fun1(a, b) + 9;
    }
}

改进

public class LiskovSubstitution2 {

    public static void main(String[] args) {
        A a = new A();
        System.out.println("10-5=" + a.fun1(10, 5));

        B b = new B();
        System.out.println("10-5=" + b.fun2(10, 5));
        System.out.println("10+5=" + b.fun1(10, 5));
    }
}

// 创建一个更加基础的类作为基类
class base {

    // 可以把更加基础的方法和成员写到此类中进行继承
}

class A extends base {

    Integer fun1(int a, int b) {
        return a - b;
    }
}

class B extends base {

    // 如果需要使用类A中的方法,这里使用组合的方式进行获取。
    private A a = new A();

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

    // 使用类A中的减法
    Integer fun2(int a, int b) {
        return this.a.fun1(a, b);
    }
}
2.5 开闭原则ocp(Open Closed Principle)
概述
  1. 开闭原则是编程中最基础、最重要的设计原则。
  2. 一个软件实体如类,模块和函数应该对扩展开放(提供方),对修改关闭(使用方),用抽象构建框架,用实现扩展细节。
  3. 当软件需要变化时,尽量通过扩展软件实体的行为来实现变化,而不是通过修改已有的代码来实现变化。
  4. 编程中遵循其他原则,以及使用设计模式的目的就是遵循开闭原则。
应用举例

类图:

 
public class OpenClosed {

    public static void main(String[] args) {

        GraphicEditor graphicEditor = new GraphicEditor();
        graphicEditor.draw(new Circle());
        graphicEditor.draw(new Rectangle());
        graphicEditor.draw(new Triangle());
    }
}

// 图形编辑器类
class GraphicEditor {

    public void draw(Shape s) {

        if (s.type == 1) {
            drawRectangle();
        } else if (s.type == 2) {
            drawCircle();
            
        } else if (s.type == 3) {
            drawTriangle();
        }
    }

    public void drawRectangle() {

        System.out.println("   正在绘制矩形");
    }

    public void drawCircle() {

        System.out.println("   正在绘制圆形");
    }

    
    public void drawTriangle() {

        System.out.println("    正在绘制三角形");
    }
}

// 图形类
class Shape {

    int type;
}

// 矩形
class Rectangle extends Shape {

    Rectangle() {
        super.type = 1;
    }
}

// 圆形
class Circle extends Shape {

    Circle() {
        super.type = 2;
    }
}


class Triangle extends Shape {

    Triangle() {
        super.type = 3;
    }
}

改进

 
public class OpenClosed2 {

    public static void main(String[] args) {

        GraphicEditor graphicEditor = new GraphicEditor();
        graphicEditor.draw(new Circle());
        graphicEditor.draw(new Rectangle());
        graphicEditor.draw(new Triangle());
        graphicEditor.draw(new Other());
    }
}

// 图形编辑器类
class GraphicEditor {

    public void draw(Shape shape) {
        shape.draw();
    }

}

// 图形类
abstract class Shape {

    int type;

    abstract void draw();
}

// 矩形
class Rectangle extends Shape {

    Rectangle() {
        super.type = 1;
    }

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

// 圆形
class Circle extends Shape {

    Circle() {
        super.type = 2;
    }

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

// 三角形
class Triangle extends Shape {

    Triangle() {
        super.type = 3;
    }

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


class Other extends Shape {

    Other() {
        super.type = 4;
    }

    @Override
    void draw() {
        System.out.println("  绘制其他图形");
    }
}
2.6 迪米特法则
概述
  1. 一个对象应该对其他对象保持最少的了解。
  2. 类与类关系越密切,耦合度越大。
  3. 迪米特法则(Demeter Principle)又叫最少知道原则,即一个类对自己依赖的类知道的越少越好。也就是说,对于被依赖的类不管怎么复杂,都尽量将逻辑封装在类的内部。
    对外除了提供public方法,不对外泄露任何信息。
  4. 迪米特法则还有个更加简单的定义:只与直接的朋友通讯。
  5. 直接的朋友:每个对象都会与其他的对象有耦合关系,只要两个对象之间有耦合关系,我们就说这两个对象是朋友关系。
    耦合的方式很多,依赖,关联,组合,聚合等。其中,我们称出现成员变量,方法参数,方法返回值中的类为直接的朋友,
    而出现局部变量中的类不是直接的朋友。也就是说,陌生的类最好不要以局部变量的实行出现在类的内部。
应用举例
 
public class Demeter {

    public static void main(String[] args) {

        // 公司管理类获取到打印所有人员的id
        CompanyManager companyManager = new CompanyManager();
        companyManager.printIdForAll(new TeamManager());
    }
}

// 球员
class Player {
    private int id;

    int getId() {
        return id;
    }

    void setId(int id) {
        this.id = id;
    }
}

// 公司职员
class Employee {
    private int id;

    int getId() {
        return id;
    }

    void setId(int id) {
        this.id = id;
    }
}

// 球队管理类
class TeamManager {

    // 获取球队所有球员
    List getAllPlayer() {

        List players = new ArrayList<>(11);
        Player player;

        // 增加11名球员到球队中
        for (int i = 0; i < 11; i++) {
            player = new Player();
            player.setId(i);
            players.add(player);
        }

        return players;
    }
}


class CompanyManager {

    // 获取公司所有职员
    List getAllEmployee() {

        List employees = new ArrayList<>(20);
        Employee employee;

        // 增加20名员工到公司中
        for (int i = 0; i < 20; i++) {
            employee = new Employee();
            employee.setId(i);
            employees.add(employee);
        }

        return employees;
    }

    void printIdForAll(TeamManager teamManager) {

        
        System.out.println("打印球员id----------------------------------");
        List allPlayer = teamManager.getAllPlayer();
        for (Player player : allPlayer) {
            System.out.println("球员ID==" + player.getId());
        }

        System.out.println("打印公司职员id-------------------------------");
        List allEmployee = getAllEmployee();
        for (Employee employee : allEmployee) {
            System.out.println("公司职员ID==" + employee.getId());
        }
    }
}

改进

 
public class Demeter1 {

    public static void main(String[] args) {

        // 公司管理类获取到打印所有人员的id
        CompanyManager companyManager = new CompanyManager();
        companyManager.printIdForAll(new TeamManager());
    }
}

// 球员
class Player {
    private int id;

    int getId() {
        return id;
    }

    void setId(int id) {
        this.id = id;
    }
}

// 公司职员
class Employee {
    private int id;

    int getId() {
        return id;
    }

    void setId(int id) {
        this.id = id;
    }
}

// 球队管理类
class TeamManager {

    // 获取球队所有球员
    List getAllPlayer() {

        List players = new ArrayList<>(11);
        Player player;

        // 增加11名球员到球队中
        for (int i = 0; i < 11; i++) {
            player = new Player();
            player.setId(i);
            players.add(player);
        }

        return players;
    }

    // 打印球员id方法
    void printPlayerId() {

        System.out.println("打印球员id----------------------------------");
        List allPlayer = getAllPlayer();
        for (Player player : allPlayer) {
            System.out.println("球员ID==" + player.getId());
        }
    }
}


class CompanyManager {

    // 获取公司所有职员
    List getAllEmployee() {

        List employees = new ArrayList<>(20);
        Employee employee;

        // 增加20名员工到公司中
        for (int i = 0; i < 20; i++) {
            employee = new Employee();
            employee.setId(i);
            employees.add(employee);
        }

        return employees;
    }

    void printIdForAll(TeamManager teamManager) {

        
        teamManager.printPlayerId();

        System.out.println("打印公司职员id-------------------------------");
        List allEmployee = getAllEmployee();
        for (Employee employee : allEmployee) {
            System.out.println("公司职员ID==" + employee.getId());
        }
    }
}
注意事项
  1. 迪米特法则的核心是降低类之间的耦合。
  2. 只是减少了每个类的不必要的依赖,因此迪米特法则只是要求降低类(对象)间的耦合关系,并不是要求他们之间完全没有依赖关系(这也是不可能的)。
2.7 合成复用原则
概述
  1. 类与类之间尽量使用依赖,组合,聚合的方式,而不是使用继承的方式。
  2. 由于一个类A仅仅是需要调用类B中的方法,那么使用依赖,组合,聚合的方式比使用继承的方式更好,这样可以降低耦合。
3 设计原则核心思想
  1. 找出应用中可能需要变化之处,把它们独立出来,不要和那些不需要变化的代码混在一起。
  2. 针对接口编程,而不是针对实现编程。
  3. 为了交互对象之间的松耦合设计而努力。
转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/328659.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号