面试官:这年轻人讲的“开闭原则”有那么点东西

391 阅读4分钟

端午假期就这么悄悄的溜走了,又要开始上班啦!各位读者假期过得怎么样?有没有吃粽子?“菜鸟”的假期过得很愉快,因为没有加班,哈哈哈!不过转念一想之后的三个月都没有额外的假期了,就很难过。哎,只能眼巴巴地盼望着,国庆假期快点到来吧!

我们总不能闲等这对吧?还是赶紧跟“菜鸟”一起学学新的知识吧!

今天给大家分享一下设计模式七大原则中的“开闭原则”,也称为OCP原则。好了闲话不多说,直接进入正文。

开闭原则”是面向对象编程中最基础和最重要的设计原则之一。我们在设计程序中使用一些设计模式和遵守相关的设计原则,都是为了可以使我们的程序可以实现“开闭”!说了这么多,那到底什么是开闭原则呢?

专业术语:

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

大家能理解这句话的含义吗?是不感觉有点懵,不太明白?这就对了,要是都明白的话那还要我写的文章干嘛?

其实这句话的开放和关闭是分两个角色来讲的。

对扩展开放:指的是我们系统中的模块、类、方法对它们的提供者(开发者)应该是开放的,提供者可以对系统进行扩展(新增)新的功能。

对修改关闭:指的是系统中的模块、类、方法对它们的使用者(调用者)应该是关闭的。使用者使用这些功能时,不会因为提供方新增了功能而导致使用者也进行相应修改。

这就是开闭原则的基本概念。可能通过文字描述大家对该原则的认识不是特别清楚与深刻。下面让我们通过一个简单的小案例来加深一下对“开闭原则”的理解。

假设有一个水果店,该水果店现在出售:“苹果、香蕉。”

代码:

// 水果店
public class FruitShop {

  // 卖水果
  public void sellFruit(Fruit fruit) {
    if (fruit.fruit_type == 1) {
      sellApple(fruit);
    } else if (fruit.fruit_type == 2) {
      sellBanana(fruit);
    }
  }

  // 卖苹果
  public void sellApple(Fruit fruit) {
    System.out.println("卖出一斤苹果!");
  }

  // 卖香蕉
  public void sellBanana(Fruit fruit) {
    System.out.println("卖出一斤香蕉!");
  }
}

// 水果的基类
public class Fruit {

  int fruit_type;
}

// 苹果
public class Apple extends Fruit {

  Apple() {
    super.fruit_type = 1;
  }
}

// 香蕉
public class Banana extends Fruit {

  Banana() {
    super.fruit_type = 2;
  }
}

现在水果店扩张,添加了一种新的水果(西瓜)。根据以上示例代码我们需要作出如下新增。

1、新增西瓜类

public class Watermelon extends Fruit {

  Watermelon() {
    super.fruit_type = 3;
  }
}

2、在FruitShop类中添加“卖西瓜”的方法。

public void sellWatermelon(Fruit fruit) {
    System.out.println("卖出一斤西瓜!");
}

3、修改FruitShop类中的sellFruit方法。

public void sellFruit(Fruit fruit) {
    if (fruit.fruit_type == 1) {
      sellApple(fruit);
    } else if (fruit.fruit_type == 2) {
      sellBanana(fruit);
    } else if(fruit.fruit_type == 3){
      sellWatermelon(fruit);
    }
}

通过以上三步就实现了增加一种水果的需求,但是大家有没有发现,这种方式虽然容易理解,可是当功能发生变动时,代码的修改量会特别大。并且这种方式也不符合“开闭原则”,大家能看出来吗?

各种各样的水果类就是“提供者”,FruitShop类就是使用这些水果类的“使用者”。开闭原则中,提到对修改关闭,但是现在当提供者新增功能后,使用者(FruitShop类)也需要修改,这就违背了该原则。

我们可以将以上代码进行如下优化:

// 水果店
public class FruitShop {

  // 卖水果的方法
  public void sellFruit(Fruit fruit) {
    fruit.sell();
  }

}

// 水果的基类
public abstract class Fruit {

  int fruit_type;

  // 出售的方法
  public abstract void sell();
}

// 苹果
public class Apple extends Fruit {

  Apple() {
    super.fruit_type = 1;
  }

  @Override
  public void sell() {
    System.out.println("卖出一斤苹果!");
  }
}

// 香蕉
public class Banana extends Fruit {

  Banana() {
    super.fruit_type = 2;
  }

  @Override
  public void sell() {
    System.out.println("卖出一斤香蕉!");
  }
}

此时当我们需要新增一种水果时,只需要提供者新增一个继承自Fruit类的子类就可以了。

// 西瓜
public class Watermelon extends Fruit {

  Watermelon() {
    super.fruit_type = 3;
  }

  @Override
  public void sell() {
    System.out.println("卖出一斤西瓜!");
  }
}

这样优化后的代码就遵守了“开闭原则”。提供方可以对系统进行扩展(对扩展开放),当系统扩展了新的功能后不会影响到使用方,使用方不需要进行修改(对修改关闭)。

通过上面的描述相信大家能看出,“开闭原则”给我们传递的思想就是:尽量通过扩展软件的模块、类、方法,来实现功能的变化,而不是通过修改已有的代码来完成。这样做就可以大大降低因为修改代码而给程序带来的出错率。

今天的分享就到这里了,感觉“菜鸟”文章写得还不错的记得点赞加关注呦!你们的支持就是我坚持下去的动力,“菜鸟”会持续输出有意义的文章。