定义

“软件实体(类、模块、函数等)应该对扩展开放,对修改关闭。”

这意味着我们应该能够添加新的功能或行为,而无需修改现有的代码。

对扩展开放 => 允许通过拓展来添加新功能或行为
对修改关闭 => 不直接修改现有代码

分析

对应到react中,首选的场景就是组件了。react的组件的props其实就是开闭原则的一个很好的例子。因为我们可以通过props添加新增行为而无需修改现有代码。

反例

下面这个组件在初期应该能工作良好,但当我们需要添加新的按钮类型时,就不得不进入组件内部进行修改,这简单直接的违反了开闭原则。

function Button(props) {
  const { type } = props;

  let icon = null;

  if (type === 'face') {
    icon = <FaceIcon />;
  }

  if (type === 'star') {
    icon = <StarIcon />;
  }

  if (type === 'like') {
    icon = <LikeIcon />;
  }

  return <button>{icon}Click me</button>;
}

function App() {
  return (
    <>
      <Button type="face" />
      <Button type="star" />
      <Button type="like" />
    </>
  );
}

正例

在下面的代码中,我们通过传入icon为组件添加了新的行为,并且没有修改现有的组件代码。

function Button(props) {
  const { icon } = props;

  return <button>{icon}Click me</button>;
}

function App() {
  return (
    <>
      <Button icon={<FaceIcon />} />
      <Button icon={<StarIcon />} />
      <Button icon={<LikeIcon />} />
    </>
  );
}

我们甚至可以更进一步,将icon重命名为prefix,这样就不仅限于icon,我们可以传递各种类型来实现我们想要的需求,让组件具有更高的灵活性。(react中的props.children也是这个道理)

function Button(props) {
  const { prefix } = props;

  return <button>{prefix}Click me</button>;
}

function App() {
  return (
    <>
      <Button prefix={<FaceIcon />} />
      <Button prefix={<StarIcon />} />
      <Button prefix={<LikeIcon />} />
    </>
  );
}

结论

通过上面的组件代码,我们可以发现应用了开闭原则的版本有以下优点:

降低风险:
直接修改现有代码可能会引入错误,导致组件不稳定。而通过扩展而不是修改,我们可以减少这种风险。

易于维护:
可以更容易地维护代码,当我们需要添加新功能时,我们只需关注新增的部分,而不必担心影响其他地方。这也有助于降低维护成本。

灵活性:
通过对扩展开放,我们可以在不修改现有代码的情况下引入新功能。这使得我们的组件更加灵活,能够适应不断变化的需求。