面向对象的七大原则

Posted yishifuping

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了面向对象的七大原则相关的知识,希望对你有一定的参考价值。

面向对象七大原则(丢了一个合成复用)

技术图片

 

单一原则

  单一原则,只得就是,所有的类,文件,接口... 单一,一个文件,一个类,一个文件,只干这一件事

遵循单一职责原的优点有:

  • 可以降低类的复杂度,一个类只负责一项职责,其逻辑肯定要比负责多项职责简单的多;
  • 提高类的可读性,提高系统的可维护性;
  • 变更引起的风险降低,变更是必然的,如果单一职责原则遵守的好,当修改一个功能时,可以显著降低对其他功能的影响。

技术图片

 

开闭原则

原理:对修改关闭,对扩展开放

   基类的子扩展。

 例子:element时间组件的使用

<div class="block">
          <span class="demonstration">日期:</span>
          <el-date-picker
            v-model="timeSpan"
            type="daterange"
            :picker-options="pickerOptions2"
            range-separator="至"
            start-placeholder="开始日期"
            end-placeholder="结束日期"
            align="right">
          </el-date-picker>
        </div>

<script>
export default {
  data() {
    return {
               // 时间范围选择
      pickerOptions2: {
        shortcuts: [
          {
            text: "最近一周",
            onClick(picker) {
              const end = new Date();
              const start = new Date();
              start.setTime(start.getTime() - 3600 * 1000 * 24 * 7);
              picker.$emit("pick", [start, end]);
            }
          },
          {
            text: "最近一个月",
            onClick(picker) {
              const end = new Date();
              const start = new Date();
              start.setTime(start.getTime() - 3600 * 1000 * 24 * 30);
              picker.$emit("pick", [start, end]);
            }
          },
          {
            text: "最近三个月",
            onClick(picker) {
              const end = new Date();
              const start = new Date();
              start.setTime(start.getTime() - 3600 * 1000 * 24 * 90);
              picker.$emit("pick", [start, end]);
            }
          }
        ],
        }
    }
}
</script>            

  原因:软件系统的功能上的可扩展性要求模块是扩展开放的,软件系统的功能上的稳定性,持续性要求是修改关闭的。根本控制需求变动风险,缩小维护成本。
  核心:用抽象构建框架,用实现类实现扩展,在不修改原有模块的基础上能扩展其功能。
  优点: 增加稳定性、可扩展性高。

里氏替换

  子类能够替换父类,出现在父类能够出现的任何地方,子类必须完全实现父类的方法。在类中调用其他类是务必要使用父类或接口,如果不能使用父类或接口,则说明类的设计已经违背了原则。覆盖或实现父类的方法时输入参数可以被放大。即子类可以重载父类的方法,但输入参数不比父类方法中的小,这样在子类代替父类的时候,调用的仍然是父类的方法。里氏替换原则是针对继承而言的,如果继承是为了实现代码重用,也就是为了共享方法,那么共享的方法应该保持不变,不被子类重新定义。如果继承是为了多态那么,而多态的前提是子类覆盖父类的方法所以将父类定义为抽象类,抽象类不能够实例化对象也就不存在替换这一说。

  

子类可以扩展父类的功能,但不能改变父类原有的功能
继承机制的优点:

代码共享,减少创建类的工作量
提高代码的重用性;
子类可以形似父类,又异于父类;
提高父类的扩展性,实现父类的方法即可随意而为;
继承机制的缺点:

继承是入侵性的(只要继承,就必须拥有父类的所有属性与方法);
降低了代码的灵活性(子类拥有了父类的属性方法,会增多约束);
增强了耦合性(当父类的常量、变量、方法被修改时,必需要考虑子类的修改)。

class Shape {
  constructor() {
	this.ant=‘蚁群‘
  }
}

class Rectangle extends Shape {
  constructor() {
	super();
    this.ant=‘蚁后‘
	this.action=‘啥也不干‘
  }

  setactions(dance) {
     this.action=dance
  }

  getArea() {
    return this.ant + this.action;
  }
}

class Square extends Shape {
  constructor() {
	super();
    this.ant=‘蚁后‘
	this.action=‘啥也不干‘
  }

  setaction(high) {
    this.action = high;
  }

  getArea() {
    return this.ant + this.action;
  }
} 

function renderLargeShapes(shapes) {
  shapes.forEach((shape) => {
  console.log(shape)
    switch (shape.constructor.name) {
      case ‘Square‘:
        shape.setaction(‘跳高‘);
		break;
      case ‘Rectangle‘:
        shape.setactions(‘跳舞‘);
		break;
    }

    let area = shape.getArea();
	console.log(area)
  })
}

let shapes = [new Rectangle(), new Square()];
renderLargeShapes(shapes);

  依赖倒转原则

  我的理解:以前的依赖都是单对单的,当你修改其中一个将影响到下一的东西的使用。依赖倒转的原则就是,多对多的原则,由以前两层模式,更改成现在的三层模式,上层,依赖抽象层,在连接到下层。

  技术图片

上层的马,牛,鸡,都依赖于跑的这个抽象类,下层的跑的方式同样依赖于中层的抽象层。

上层的每一项都可以去调用到下层的每一项(多对多的关系),当想添加上层事物,或添加下层的方式,都不会影响到其他的事件,能够快速的的进行开发,减少更改代码的周期。

以上是我的理解

以下是系统解释:

依赖倒置原则的优点
  可以通过抽象使各个类或模块的实现彼此独立,不互相影响,实现模块间的松耦合(也是本质)
  可以规避一些非技术因素引起的问题(项目大时,需求变化的概率也越大,通过采用依赖倒置原则设计的接口或抽象类对实现类进行约束,可以减少需求变化引起的工作量剧增情况。同时,发生人员变动,只要文档完善,也可让维护人员轻松地扩展和维护)
  可以促进并行开发(如,两个类之间有依赖关系,只要制定出两者之间的接口(或抽象类)就可以独立开发了,规范已经定好了,而且项目之间的单元测试也可以独立地运行,而TDD开发模式更是DIP的最高级应用(特别适合项目人员整体水平较低时使用))

技术图片

  1. 模块间的依赖通过抽象类或接口发生,实现类之间的依赖关系也是通过抽象类或接口产生(实现类之间不应发生直接的依赖关系),降低系统的耦合性 
  2. 接口或抽象不依赖于实现类,但实现类依赖接口或抽象类,实现类对系统需要的功能具体实现,提高类的内聚程度

上段代码,来理解下,不知道我理解的对不对了

<html>
<head></head>
    <body>
    </body>
    <script>
class Shape {
  constructor() {
	this.ant=‘蚁群‘
  }
}

class sheep {
  constructor() {
	this.ant=‘羊群‘
  }
}

class Rectangle extends Shape {
  constructor() {
	super();
    this.ant=‘蚁后‘
	this.action=‘啥也不干‘
  }

  getArea() {
    return this.ant + this.action;
  }
}

class Square extends sheep {
  constructor() {
	super();
    this.ant=‘羊群‘
	this.action=‘吃草‘
  }

  getArea() {
    return this.ant + this.action;
  }
} 

function renderLargeShapes(shapes) {
  shapes.forEach((shape) => {
  console.log(shape)
    switch (shape.constructor.name) {
      case ‘Square‘:
		break;
      case ‘Rectangle‘:;
		break;
    }

    let area = shape.getArea();
	console.log(area)
  })
}

let shapes = [new Rectangle(), new Square()];
renderLargeShapes(shapes);
       </script>
</html>

  接口隔离

1、官方定义

接口隔离原则,英文缩写ISP,全称Interface Segregation Principle。

原始定义:Clients should not be forced to depend upon interfaces that they don’t use,还有一种定义是The dependency of one class to another one should depend on the smallest possible interface。

官方翻译:其一是不应该强行要求客户端依赖于它们不用的接口;其二是类之间的依赖应该建立在最小的接口上面。简单点说,客户端需要什么功能,就提供什么接口,对于客户端不需要的接口不应该强行要求其依赖;类之间的依赖应该建立在最小的接口上面,这里最小的粒度取决于单一职责原则的划分。

接口隔离原则和单一职责原则

从功能上来看,接口隔离和单一职责两个原则具有一定的相似性。其实如果我们仔细想想还是有区别的。

(1)从原则约束的侧重点来说,接口隔离原则更关注的是接口依赖程度的隔离,更加关注接口的“高内聚”;而单一职责原则更加注重的是接口职责的划分。

(2)从接口的细化程度来说,单一职责原则对接口的划分更加精细,而接口隔离原则注重的是相同功能的接口的隔离。接口隔离里面的最小接口有时可以是多个单一职责的公共接口。

(3)单一职责原则更加偏向对业务的约束,接口隔离原则更加偏向设计架构的约束。这个应该好理解,职责是根据业务功能来划分的,所以单一原则更加偏向业务;而接口隔离更多是为了“高内聚”,偏向架构的设计。

以上官方定义

以下自己理解:

  我认为,接口隔离,就是把以前的一个接口调3,4个东西,完咯给分割一下,把多个东西拆成安区域,功能区分割一下它。如图

没有进行隔离的图样:一个事件,把所有的都给调出来了

技术图片

经过隔离后的样事:简单分离下(但不符合单一原则)

技术图片

其实我感觉吧,当你使用了 单一原则后,你所谓的接口隔离原则,好像就没有什么用了,毕竟单一原则上面讲了,一个接口调用一件事,就不存在一调多了

里米特法则:

以上是关于面向对象的七大原则的主要内容,如果未能解决你的问题,请参考以下文章

面向对象七大设计原则

面向对象七大原则

程序员七大面向对象设计原则

面向对象的七大原则

七大面向对象设计原则

面向对象设计的七大基本原则