简介
开闭原则(Open-Closed Principle,OCP)是面向对象设计中的一个重要原则,由勃兰特·梅耶(Bertrand Meyer)在他的著作《面向对象软件构造》(Object-Oriented Software Construction)中首次提出。这个原则强调软件实体(类、模块、函数等)应该对扩展开放,对修改关闭。换句话说,当需要改变系统的行为或者添加新功能时,应该尽量避免修改已有的代码,而是通过扩展已有的代码来实现变化。
具体来说,开闭原则包含以下两个核心概念:
开放性(Open for Extension):软件实体应该允许在不修改已有代码的情况下进行扩展。这意味着应该设计软件结构以便可以新增功能,而不需要修改现有的代码。
封闭性(Closed for Modification):软件实体在扩展时不应该修改其已有的代码。这意味着对已有的代码进行修改时应该小心谨慎,避免因此引入新的错误或导致已有功能的失效。
开闭原则的实现通常通过一些设计模式来完成,例如策略模式、观察者模式、装饰者模式等。这些模式使得系统更易于扩展,同时保持了系统的稳定性和可维护性。
违法开闭原则示例
public interface Noodle {
/**
* 制作接口类
* @author yiridancan
**/
void cook();
}
/**
* 牛肉面实现类
* @author yiridancan
**/
public class BeefNoodle implements Noodle{
@Override
public void cook() {
System.out.println("牛肉面正在准备中...");
}
}
/**
* 鸡肉面实现类
* @author yiridancan
**/
public class ChickenNoodle implements Noodle{
@Override
public void cook() {
System.out.println("鸡肉面正在准备中...");
}
}
/**
* 素面实现类
* @author yiridancan
**/
public class VegetarianNoodle implements Noodle{
@Override
public void cook() {
System.out.println("素面正在准备中...");
}
}
/**
* 简单工厂类
* @author yiridancan
**/
public class NoodleFactory {
public static Noodle getNoodle(String type){
switch (type){
case "beef":
return new BeefNoodle();
case "chicken":
return new ChickenNoodle();
case "vegetarian":
return new VegetarianNoodle();
default:
return null;
}
}
}
@Test
public void factoryTest(){
//鸡肉面
Noodle chicken = NoodleFactory.getNoodle("chicken");
chicken.cook();
//牛肉面
Noodle beef = NoodleFactory.getNoodle("beef");
beef.cook();
//素面
Noodle vegetarian = NoodleFactory.getNoodle("vegetarian");
vegetarian.cook();
}
当我们需要增加面的类型时,比如排骨面。这个时候我们就需要先定义一个RibsNoodle类,其中实现排骨面的代码。除此之外我们还要修改NoodleFactory
类的代码,增加一个case。这显然是违背开闭原则的
符合开闭原则示例
public interface NoodleFactory {
/**
* 面条工厂接口
* @author yiridancan
**/
Noodle createNoodle();
}
/**
* 具体的工厂类:牛肉面工厂
* @author yiridancan
**/
public class BeefNoodleFactory implements NoodleFactory{
@Override
public Noodle createNoodle() {
return new BeefNoodle();
}
}
/**
* 具体的工厂类:鸡肉面工厂
* @author yiridancan
**/
public class ChickenNoodleFactory implements NoodleFactory{
@Override
public Noodle createNoodle() {
return new ChickenNoodle();
}
}
/**
* 具体的工厂类:素面工厂
* @author yiridancan
**/
public class VegetarianNoodleFactory implements NoodleFactory{
@Override
public Noodle createNoodle() {
return new VegetarianNoodle();
}
}
@Test
public void factoryTest(){
// 创建牛肉面工厂,并制作牛肉面
NoodleFactory beefNoodleFactory = new BeefNoodleFactory();
Noodle beefNoodle = beefNoodleFactory.createNoodle();
beefNoodle.cook();
// 创建鸡肉面工厂,并制作鸡肉面
NoodleFactory chickenNoodleFactory = new ChickenNoodleFactory();
Noodle chickenNoodle = chickenNoodleFactory.createNoodle();
chickenNoodle.cook();
// 创建素面工厂,并制作素面
NoodleFactory vegetarianNoodleFactory = new VegetarianNoodleFactory();
Noodle vegetarianNoodle = vegetarianNoodleFactory.createNoodle();
vegetarianNoodle.cook();
}
在这个示例中,我们结合了策略模式和工厂模式。首先,我们定义了面条接口 Noodle
和具体的面条类:BeefNoodle
、ChickenNoodle
和 VegetarianNoodle
。
然后,我们定义了面条工厂接口 NoodleFactory
和具体的面条工厂类:BeefNoodleFactory
、ChickenNoodleFactory
和 VegetarianNoodleFactory
。每个工厂类负责创建对应类型的面条。
最后,测试代码中,我们根据需要创建不同的面条工厂,并调用工厂的 createNoodle
方法来创建不同类型的面条对象,然后调用 cook
方法来制作面条。这样一来,当需要新增一种面条类型时,只需创建对应的工厂类即可,不需要修改已有的工厂类或其他已有的代码,符合开闭原则。