ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

设计模式-七大设计原则

2021-11-14 17:33:47  阅读:165  来源: 互联网

标签:原则 void 七大 class vehicle println 设计模式 public out


七大设计原则

在软件开发中,为了提高软件系统的可维护性、复用性、可扩展性、可靠性、灵活性,让程序呈现出高内聚、低耦合。程序员需要尽量根据七条原则来开发程序,从而提高软件开发效率、节约软件开发成本和维护成本

参考链接:

黑马Java设计模式详解

尚硅谷Java设计模式

设计模式系列之设计原则(5)迪米特法则

一、单一职责原则

其核心思想为:一个类,最好只做一件事,只有一个引起它的变化

通常意义下的单一职责,就是指只有一种单一功能,不要为类实现过多的功能点,以保证实体只有一个引起它变化的原因。

单一职责原则可以看做是低耦合、高内聚在面向对象原则上的引申,
将职责定义为引起变化的原因,以提高内聚性来减少引起变化的原因。
职责过多,可能引起它变化的原因就越多,这将导致职责依赖,相互之间就产生影响,从而大大损伤其内聚性和耦合度

public class SingleResponsibility_1 {
    public static void main(String[] args) {
        Vehicle vehicle = new Vehicle();
        vehicle.run("汽车");
        vehicle.run("飞机");
    }

    //交通工具类
    // 方式一:此时Vehicle中的run方法既管公路上跑的,又管天上飞的,违反了单一原则
    // 解决方案:根据交通工具运行方法不同,分解成不同类
    static class Vehicle{
        //方式一:
        public void run(String vehicle){
            System.out.println(vehicle + " 在公路上跑");
        }
    }
}
public class SingleResponsibility_2 {
    public static void main(String[] args) {
        new RoadVehicle().run("汽车");
        new AirVehicle().run("飞机");
    }
    
    /**
     * 方式二:
     * 1. 遵守单一职责原则
     * 2. 但是改动太大,又要分解类,又要修改客户端
     * 改进方案:修改Vehicle类,改动的代码会比较少
     */
    static class RoadVehicle{
        public void run(String vehicle){
            System.out.println(vehicle + " 在公路上跑");
        }
    }

    static class AirVehicle{
        public void run(String vehicle){
            System.out.println(vehicle + " 在天上飞");
        }
    }

    static class WaterVehicle{
        public void run(String vehicle){
            System.out.println(vehicle + " 在水里游");
        }
    }
}

如果严格遵守单一职责原则,那么可以造成类急速增多,维护性反而下降

所以当类中逻辑简单,类中方法足够少,我们可以在方法级别保持单一职责原则

public class SingleResponsibility_3 {
    public static void main(String[] args) {
        Vehicle vehicle = new Vehicle();
        vehicle.runRoad("汽车");
        vehicle.runWater("船");
        vehicle.runAir("飞机");
    }

    /**
     * 方式三:
     * 1. 这种修改方法没有对原来的类做大的修改,只是增加方法
     * 2. 这里虽然没有在类级别遵守单一职责,但是在方法级别上遵守单一职责
     */
    static class Vehicle{
        public void runRoad(String vehicle){
            System.out.println(vehicle + " 在公路上跑");
        }

        public void runAir(String vehicle){
            System.out.println(vehicle + " 在天上跑");
        }

        public void runWater(String vehicle){
            System.out.println(vehicle + " 在水里跑");
        }
    }
}

二、开闭原则

软件实体应该是可扩展的,并且不可修改的,对扩展开放,对修改关闭

实现:借助于抽象类和接口

public abstract class AbstractSkin {
    abstract public void display();
}
//AbstractSkin的两个子类
public class DefaultSkin extends AbstractSkin{
    @Override
    public void display() {
        System.out.println("默认");
    }
}

public class HeimaSkin extends AbstractSkin{
    @Override
    public void display() {
        System.out.println("黑马");
    }
}
public class SougouInput {
    private AbstractSkin skin;

    public void setSkin(AbstractSkin skin) {
        this.skin = skin;
    }

    public void display(){
        skin.display();
    }

    public static void main(String[] args) {
        SougouInput input = new SougouInput();
		
        //如下例所示,搜狗皮肤的设置依赖于AbstractSkin
        //如果要扩展搜狗皮肤,只需在写一个AbstractSkin的子类即可
        //input.setSkin(new DefaultSkin());
        input.setSkin(new HeimaSkin());

        input.display();
    }
}

三、里氏代换原则

  • 任何基类可以出现的地方,子类一定可以出现。
  • 本质上:子类可以扩展父类的功能,但不能改变父类原有的功能。
  • 换句话说子类继承父类时,除了添加新的方法完成新增功能外,尽量不要重写父类的方法
  • 好处:
    • 如果重写父类的方法来完成新的功能,这样写起来虽然简单,但是整个继承体系的可复用性会比较差。
      特别是多态使用频繁时,程序运行出错的概率会非常大。
    • 提高继承体系的可复用性,保证使用多态时不出错。

违背里氏代换的情况

//长方形
public class Rectangle {
    private double length;
    private double width;
    
    public double getWidth() return width;
    public void setWidth(double width) this.width = width;
    public double getLength() return length;
    public void setLength(double length) this.length = length;
}
//正方形
//这里的正方形,重写了长方形中的set方法
//保证了长与宽的相等。
public class Square {
    @Override
    public void setWidth(double width) {
        super.setWidth(width);
        super.setLength(width);
    }

    @Override
    public void setLength(double length) {
        super.setLength(length);
        super.setWidth(length);
    }
}
public class RectangleDemo {
    //扩宽方法
    public static void resize(Rectangle rectangle){
        while(rectangle.getWidth() <= rectangle.getLength()){
            rectangle.setWidth(rectangle.getWidth() + 1);
        }
    }
    //测试
    public static void main(String[] args) {
        Rectangle rectangle = new Rectangle();
        rectangle.setWidth(10);
        rectangle.setLength(20);
        //这里对长方形进行扩宽,没有问题
        resize(rectangle);
        System.out.println("==========================");
        Square square = new Square();
        square.setWidth(10);
        //square是rectangle子类,可以使用多态
        //但由于改写了set方法,square中的长宽一直相等,导致程序陷入死循环
        //而里氏代换原则中基类出现的地方,子类一定能出现。这里显然不满足。
        //这里子类改写了父类的方法,那么在多态中容易引发错误
        resize(square);
    }
}

根据里氏代换原则改进

//四边形
public interface Quadrilateral {
    double getLength();
    double getWidth();
}
public class Rectangle implements Quadrilateral{
    private double length;
    private double width;

    public void setLength(double length) { this.length = length; }
    public void setWidth(double width) { this.width = width; }
    @Override
    public double getLength() { return length; }
    @Override
    public double getWidth() { return width; }
}

四、依赖倒转原则

高层模块不应该依赖底层模块,两者都应该依赖其抽象;抽象不应该依赖细节,细节应该依赖抽象。

简单的说:就是对抽象编程,不要对实现编程,这样就降低了客户与实现模块间的耦合。

组合关系: 整体类对象 能管理 部分对象的 生命周期。整体归西,部分必归西。
聚合关系: 整体类对象 能利用 部分对象,而不能管理部分对象生命周期。整体归西,部分不一定归西。

违反依赖倒转原则案例

public Class IntelCpu {
    public void run(){
        System.out.println("cpu is running...");
    }
}
public Class XiJieHardDisk {
    public void get(){
        System.out.println("getting data from XiJieHardDisk");
    }
    public void save(){
        System.out.println("save data to XiJieHardDisk");
    }
}
public Class Computer {
    private IntelCpu cpu;
    private XiJieHardDisk hardDisk;
    
    public void setIntelCpu(IntelCpu cpu) this.cpu = cpu;
    public void setXiJieHardDisk(XiJieHardDisk hardDisk) this.hardDisk = hardDisk;
    
    //这里是面向实现类编程,简单易懂,但扩展不方便
    //cpu用别的还得改代码,硬盘hardDisk也是如此
    public void run(){
        hardDisk.get();
        cpu.run();
        hardDisk.save();
    }
}

用依赖倒转原则改进

public interface Cpu {
    void run();
}
public interface HardDisk {
    void get();
    void save();
}
public Class Computer {
    //成员变量 使用接口,而不是实现类
    //所以现在可以给Cpu设置cpu接口的多种实现类了
    private Cpu cpu;
    private HardDisk hardDisk;

    public void setCpu(Cpu cpu) this.cpu = cpu;
    public void setHardDisk(HardDisk hardDisk) this.hardDisk = hardDisk;
    
    public void run(){
        hardDisk.get();
        cpu.run();
        hardDisk.save();
    }
}

五、接口隔离原则

接口隔离原则也叫最小接口原则
本质就是不应该让类被迫依赖它不使用的方法
一个类对另一个类的依赖应该简历在最小的接口上

  • 违背接口隔离的例子:
public class Segregation_1 {
    /**
     * 显然,
     * 类B,类D都是Interface1的实现类,都实现了Interface1的五种方法
     * 类A通过接口依赖类B,类C通过接口依赖类D
     * 如果接口对于类A和类C来说不是最小接口(即没有用到接口中的所有非default方法)
     * 那么则会违反接口隔离原则
     *
     * 使用接口隔离原则改进
     * 处理方法:把接口拆分独立的几个接口,类A和类C分别与他们需要的接口进阿里依赖关系。
     */
    interface Interface1 { void method1(); void method2(); void method3(); }

    class B implements Interface1 {
        @Override
        public void method1() { System.out.println("B-method1"); }

        @Override
        public void method2() { System.out.println("B-method2"); }

        @Override
        public void method3() { System.out.println("B-method3"); }
    }

    class D implements Interface1 {
        @Override
        public void method1() { System.out.println("D-method1"); }

        @Override
        public void method2() { System.out.println("D-method2"); }

        @Override
        public void method3() { System.out.println("D-method3"); }
    }

    //A类通过接口依赖B类,但只用到method1、method2
    class A {
        public void depend1(Interface1 interface1){ interface1.method1(); }
        public void depend2(Interface1 interface2){ interface2.method2(); }
    }

    //C类通过接口依赖D,但只用到method1、method3
    class C {
        public void depend1(Interface1 inf){ inf.method1(); }
        public void depend3(Interface1 inf){ inf.method3(); }
    }
}
  • 改进,改进的话,只需把接口拆分为多个,让实现类B、D实现多个接口即可

六、迪米特法则

迪米特法则也叫最少知识原则
只和你的直接朋友说话,不跟“陌生人”说话

  • 含义

    如果两个软件实体无须直接通信,那么就不应该发生直接的相互调用,可以通过第三方转发该调用。

  • 目的:降低类的耦合度,提高模块的相对独立性

  • 迪米特法则中的朋友是指:(这些对象存在关联、聚合或组合关系,可以直接访问这些对象的方法)

    • 当前对象本身
    • 当前对象的成员对象
    • 当前对象所创建的对象
    • 当前对象的方法参数等。

违背迪米特法则的案例:

//老板类
//此时老板需要拿到员工类,让员工打印名字。
//但员工类不是老板类的朋友,因此这个老板类的设计不符合迪米特法则。
public class Boss {
    public void  getEmloye(TeamLeader teamLeader){
        //此处的employ是其他对象方法的返回值,不属于boss的朋友
        Employe employ = teamLeader.getEmploy();
        System.out.println(employ.getName());
    }
}
//项目组长类
public class TeamLeader {
    //返回一个员工对象
    public Employe getEmploy(){
        return new Employe("张三");
    }
}
//员工类
public class Employe{
    private String name;
    public setName(String name) this.name = name;
    public getName() return this.name;
}

改进:

//老板类
public class Boss {
    public void  getEmloye(TeamLeader teamLeader){
        //同员工通信细节完全交给项目组长实现
        //老板类不直接同员工类通信
        teamLeader.getEmploy();
    }
}
//项目组长类
public class TeamLeader {
    public void getEmploy(){
        System.out.println(new Employe("张三").getName());
    }
}

七、合成复用原则

尽量先使用组合或者聚合等关联关系来实现,其次才考虑使用继承关系来实现。

通常类的复用分为继承复用和合成复用两种。

继承复用虽然简单易于实现,但也存在以下缺点:

  1. 继承复用破坏了类的封装性。因为继承会将父类的试下细节暴露给子类,父类对子类是透明的,所以这种复用又称为”白箱“复用
  2. 子类与父类的耦合度高。父类的实现的任何改变都会导致子类的实现发生裱花,这不利于类的扩展与维护
  3. 它限制了复用的灵活性。从父类继承而来的实现是静态的,在编译时已经定义,所以在运行时不可能发生变化。

采用组合或聚合复用时,可以将已有对象纳入新对象中,使之称为新对象的一部分,新对象可以调用已有对象的功能,其有以下优点:

  1. 它维持了类的封装性。因为成员对象的内部细节是新对象看不见的,所以这种复用又称为”黑箱“复用
  2. 对象之间的耦合度低。可以在类的成员位置声明抽象
  3. 复用的灵活性高。这种复用可以在运行时动态进行,新对象可以动态地引用与成员对象类型相同的对象

用继承的情况

继承复用,简单易于实现,但一旦扩展,则要生成多个类。

用接口的情况

合成复用,扩展只需生成一个类

标签:原则,void,七大,class,vehicle,println,设计模式,public,out
来源: https://www.cnblogs.com/funfe/p/15552500.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有