S.O.L.I.D 原则 with JavaScript

S.O.L.I.D 原则 with JavaScript

  • S: Single responsibility principle
  • O: Open closed principle
  • L: Liskov substitution principle
  • I: Interface segregation principle
  • D: Dependency Inversion principle

Single Responsibility Principle

A class should have one and only one reason to change,meaning that a class should only have one job.

单一责任原则。

Open Closed Principle

Objects or entities should be open for extension, but closed for modification.

开闭原则。允许扩展,禁止修改。

在这个原则下鼓励使用接口和函数组合而不是继承。

以下是 JS 实现接口的方式。由于 JS 没有 Class 只有 Object,且采用对象原型继承的方法,因此在语言层面是没有接口概念的,但可以通过一些手段去实现接口。

  • 使用 Typescript 来实现接口
interface ShapeInterface { 
 area(): number 
}  
class Circle implements ShapeInterface {     
 let radius: number = 0     
 constructor (r: number) {        
  this.radius = r     
 }      
 
 public area(): number { 
  return MATH.PI * MATH.pow(this.radius, 2)
 } 
}
  • 使用 Functions Composition
/**
* 定义接口
* 该接口约定传入的对象 `state` 必须有一个 `area` 方法
* 也就是间接的约定
*/
const shapeInterface = (state) => ({
  type: 'shapeInterface',
  area: () => state.area(state),
});
/**
* 定义工厂函数
* 用于创建 `square` 对象
*/
const square = (length) => {
  // 定义原型实现 `shapeInterface` 约定的 `area` 方法
  const proto = {
    length,
    type: 'Square',
    area: (args) => Math.pow(args.length, 2),
  };
  // 实现接口
  const basics = shapeInterface(proto);
  const composite = Object.assign({}, basics);
  // 返回新的 `square` 对象
  return Object.assign(Object.create(composite), { length });
};

const s = square(5);
console.log(`OBJ\n${JSON.stringify(s)}`);
console.log(`PROTO\n${Object.getPrototypeOf(s)}`);
console.log(s.area());

Liskov Substitution Principle

Let q ( x ) q(x) q(x) be a property provable about objects of x x x of type T T T. The q ( y ) q(y) q(y) should be provable for objects y y y of types S S S where S S S is a subtypes of T T T.

里氏替换原则。任意子类都可以替换它们的父类。也就是说,子类可以改写其父类的方法,且站在使用者的角度来看不会破坏原有的功能。

下面的列子很好的说明了 Liskov Substitution Principle。该范例源自SOLID JavaScript: The Liskov Substitution Principle

function Vehicle(my) {
    my = my || {};
    my.speed = 0;
    my.running = false;

    this.speed = function() {
        return my.speed;
    };
    this.start = function() {
        my.running = true;
    };
    this.stop = function() {
        my.running = false;
    };
    this.accelerate = function() {
        my.speed++;
    };
    this.decelerate = function() {
        my.speed--;
    };
    this.state = function() {
        if (!my.running) {
            return "parked";
        }
        else if (my.running && my.speed) {
            return "moving";
        }
        else if (my.running) {
            return "idle";
        }
    };
}
function FastVehicle(my) {
    my = my || {};
    
    var that = new Vehicle(my);
    that.accelerate = function() {
        my.speed += 3;
    };
    return that;
}
var maneuver = function(vehicle) {
    write(vehicle.state());
    vehicle.start();
    write(vehicle.state());
    vehicle.accelerate();
    write(vehicle.state());
    write(vehicle.speed());
    vehicle.decelerate();
    write(vehicle.speed());
    if (vehicle.state() != "idle") {
        throw "The vehicle is still moving!";
    }
    vehicle.stop();
    write(vehicle.state());
};

子类 FastVehicle 改写了父类 Vehicleaccelerate 函数,导致客户端程序发生异常(即车应该停止了却仍在运行)。导致该问题的原因是,应该将 decelerate 一并改写。

上面的例子很形象的解释了什么是 Liskov Substitution Principle,以及违反了该原则后带来的问题。

那么如何规避违反 Liskov Substitution Principle 呢,以下是给出的建议

  • 尽量避免继承(Inheritance),而采用契约(Contracts)

契约有两种主要形式:可执行规范和错误检查。

Interface Segregation Principle

A client should never be forced to implement an interface that it doesn’t use or clients shouldn’t be force to depend on methods they do not use.

接口分离原则。简而言之,将接口尽可能拆分成小接口。

Dependency Inversion Principle

Entities must depend on abstractions not on concretions. It states that the high level module must not depend on the low level module, but they should depend on abstractions.

依赖反转原则。

From a functional point of view, these containers and injection concepts can be solved with a simple higher order function, or hole-in-the-middle types pattern which are built right into the language.

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值