开闭原则

说到面向对象设计,大部分人脑海中闪过的恐怕都是“23种设计模式”。设计模式代表的是业务场景中总结出的最佳实现方式,属于实践的范畴,在其之上是更为重要的“SOLID”五大原则:

  • Single Responsibility Principle 单一责任原则
  • The Open Closed Principle 开放封闭原则
  • The Liskov Substitution Principle 里氏替换原则
  • The Dependency Inversion Principle 依赖倒置原则
  • The Interface Segregation Principle 接口分离原则

SOLID 五大原则的出发点也是软件工程的终极目标:“高内聚、低耦合”。在后端开发中运用最多的是“依赖倒置原则”,与其相关的设计模式大约有5-6个。如下图所示:

https://app.yinxiang.com/FileSharing.action?hash=1/cdbb94425672b019aa8f79d9c808cdb8-20964

上图也可以理解为从抽象概念到具体实践的逐步演进。

在前端技术框架中,运用最多的是“开放封闭原则”,我们先来看一下这条原则是怎么定义的:

A software artifact should be open for extension but closed for modification.

翻译过来就是:软件系统应当对扩展开放,对修改封闭(感觉像没说)。这里举一个简单的例子来说明开闭原则,先帮助大家理解概念:

public  abstract  class  Shape
{    
    public  abstract double  Area();
}
public  class  Rectangle:  Shape
{    
    public  double Width 
    { 
        get; 
        set;
    }    
    public  double Height 
    { 
        get; 
        set;
    }    
    public  override double  Area()    
    {         
        return  Width * Height   
    }
}
public  class  Circle:  Shape
{    
    public  double Radius 
    { 
        get; 
        set
    }    
    public  override double  Area()    
    {        
        return  Radius * Radius * PI;    
    }
}
public  double  Area(Shape []  shapes)
{   
    doubel area  =  0;   
    foreach (var  shape  in  shapes)    
    {       
        area  +=  shape.Area();    
    }    
    return  area;
}

上例中无论场景如何扩展,Area 函数都无需修改,每个 Shape 类通过继承接口和多态特性,各自实现面积计算。

总结一下开闭原则就是:软件系统的核心逻辑都不应该轻易改变,否则会破坏系统的稳定性和增加测试成本。我们应当建立合适的抽象并统一接口,当业务需要扩展时,我们可以通过增加实体类来完成。

接下来我们看一个“开闭原则”在前端框架中的应用: Ant Design 组件库中的 Form 表单组件。

和其它组件不同,Form 组件并没有具体的形态,它更像是一个容器,提供了接入的标准,并提供了校验、表单提交等功能。绘制表单中的一项如下所示:

<FormItem>  {getFieldDecorator('userName', {     rules: [{ required: true, message: 'Please input your username!' }],     })(<Input prefix={<Icon type="user" style={{ color: 'rgba(0,0,0,.25)' }} />}        placeholder="Username" />   )}</FormItem>

Ant Design 组件库中已经提供个几乎所有的常见表单组件,如:Select 、Checkbox 、Radio 、Cascader 等,但在实际业务中,我们还是会需要设计业务相关的表单项,Form 表单通过统一组件接口的方式满足了这个技术需求,具体规约如下:

自定义或第三方的表单控件,也可以与 Form 组件一起使用。只要该组件遵循以下的约定:

  • 提供受控属性 value 或其它与 valuePropName 的值同名的属性。
  • 提供 onChange 事件或 trigger 的值同名的事件。
  • 不能是函数式组件。

具体例子

这正是“开闭原则”的一个典型实践案例,即表单核心逻辑(校验、提交等)保持不变并封装在 Form 组件中,自定义表单项只需要满足上述三条规约,就能平滑接入到 Form 组件中,和 Ant Design 原生组件契合在一起。

Ant Design 中的 Form 组件通过这样一个简洁的设计,完美提供了表单类型页面的统一解决方案。