开闭固原则条件失败
Posted
技术标签:
【中文标题】开闭固原则条件失败【英文标题】:Open close solid principle conditional fails 【发布时间】:2021-08-12 20:24:17 【问题描述】:根据SOLID的开闭原则,类对扩展开放,对修改关闭。
所以我可以根据新的 if-else 条件添加新逻辑吗?
如果我不使用条件,那么我将如何根据哪个条件确定必须应用哪个操作
public interface TemplateClassification
QuesObj processTemplate(RawPart rawPart);
public class Template1 implements TemplateClassification
@Override
public QuesObj processTemplate(RawPart rawPart)
return new QuesObj("Hi header 1"+rawPart.getHead(),"Hi I am footer 1"+rawPart.getFoot());
public class Template2 implements TemplateClassification
@Override
public QuesObj processTemplate(RawPart rawPart)
return new QuesObj("Hi header 2"+rawPart.getHead(),"Hi I am footer "+rawPart.getFoot());
public class TemplateInfo
private TemplateClassification templateClassification;
public TemplateClassification getTemplateClassification()
return templateClassification;
public void setTemplateClassification(TemplateClassification templateClassification)
this.templateClassification = templateClassification;
public class TemplateProduct
public QuesObj calculateTemplate(TemplateInfo templateInfo,RawPart rawPart)
QuesObj ques = templateInfo.getTemplateClassification().processTemplate(rawPart);
return ques;
@RestController
class Pg
@Autowired
TemplateInfo templateInfo;
@Autowired
TemplateProduct templateProduct;
public doProcessing(RawPart rawPart)
QuesObj ques = null;
if(rawPart.getId() == 1)
Template1 temp = new Template1();
ques = templateProduct.calculateTemplate(templateInfo,rawPart);
elseIf(rawPart.getId() == 2)
Template2 temp = new Template2();
ques = templateProduct.calculateTemplate(templateInfo,rawPart);
elseIf(tempId == 3)
// coming soon
如何消除 if else 条件,使其遵循开闭原则
【问题讨论】:
【参考方案1】:要在 SOLID 中实现“O”,您可以按照以下步骤操作,其中也包括“S”。
我们将使用多态和继承。
第 1 步:
创建一个位于负责创建 QuesObj 的类前面的接口。我们将需要这个,因为当 id 为 1,2 或 3 时,代码可以接收创建者(子类)。
请务必注意,已识别 QuesObj 是因为它会在您的原始 if 语句中返回,这也是我们被允许继续使用此方法的原因。
public interface QuesObjCreator
QuesObj calculate(RawPart rawPart);
第 2 步:
在该类的唯一作用是创建对象。
public class QuesObjCreatorFor1 implements QuesObjCreator
private TemplateInfo templateInfo;
private TemplateProduct templateProduct;
@Override
public QuesObj calculate(RawPart rawPart)
Template1 temp = new Template1();
return templateProduct.calculateTemplate(templateInfo,rawPart);
public class QuesObjCreatorFor2 implements QuesObjCreator
private TemplateInfo templateInfo;
private TemplateProduct templateProduct;
@Override
public QuesObj calculate(RawPart rawPart)
Template2 temp = new Template2();
return templateProduct.calculateTemplate(templateInfo,rawPart);
第 3 步:
创建工厂以返回 QuesObjCreator。工厂将返回到您的主要代码/服务。
public class QuesObjectCreatorFactory
private static final Map<Integer,QuesObjCreator> quesObjCreatorMap = new HashMap<>();
public QuesObjectCreatorFactory()
quesObjCreatorMap.put(1,new QuesObjCreatorFor1());
quesObjCreatorMap.put(2,new QuesObjCreatorFor2());
public static QuesObjCreator getQuesObjCreator(final int number)
final QuesObjCreator quesObjCreator = quesObjCreatorMap.get(number);
if(quesObjCreator == null)
throw new IllegalArgumentException("QuesObj for "+number+" does not exist");
return quesObjCreator;
第 4 步:
使用工厂创建 QuesObj
public class Pg
public void doProcessing(RawPart rawPart)
final QuesObjCreator quesObjCreator = QuesObjectCreatorFactory.getQuesObjCreator(rawPart.getId());
QuesObj ques = quesObjCreator.calculate(rawPart);
我们共同实现了跨所有类的单一职责并解耦。
易于维护,因为现在您可以添加更多选项来创建 QuesObj,并且不会更改任何代码,从而实现开放可扩展/封闭可修改。
这一切都归结为拥有创作者的工厂和地图。必须使用所有创建者实例填充地图。使用 Spring,这非常容易,因为 Spring 可以扫描您的项目,查找特定类型的 bean,给您一个 List,然后您可以将其转换为 map。
【讨论】:
您好,感谢您的回答,但我相信quesObjCreatorMap
的大小在课堂上将始终为 0 秒 QuesObjCreatorFor2
和 QuesObjCreatorFor2
temp
从未使用过
我相信这也是一种工厂模式。
@Beginner 正确,即来自OP原始代码。【参考方案2】:
您的案例与 SOLID 无关。根据开闭原则,你不能允许在运行时修改你的类,这会破坏它的行为。
在你的情况下,我建议如下:
将getId()
方法添加到您的 TemplateClassification 接口。
使每个 TemplateClassification 实现成为一个 bean
添加将为您形成模板映射的 bean
@Bean
public Map<Integer, TemplateClassification> templates(List<TemplateClassification> templates)
return algorithms.stream()
.collect(Collectors.toMap(TemplateClassification::getId, Function.identity()));
将Map<Integter, TemplateClassification> templates
自动连接到您的控制器并通过 id 找到所需的模板。
【讨论】:
以上是关于开闭固原则条件失败的主要内容,如果未能解决你的问题,请参考以下文章