让我们试着反省一下以上声明:一旦编写,就不应修改软件实体以添加新功能,而必须对其进行扩展以添加新功能。
换句话说,您不会触摸现有模块,因此不会干扰现有功能,而是您可以扩展模块以实现新要求。 因此,您的代码不那么僵化,脆弱,也可以扩展。
OCP术语由Bertnard Meyer创造。
我们如何确认OCP原则?
简单-允许模块(类)依赖抽象,可以通过创建这些抽象的新扩展来添加新功能。
让我尝试用一个例子来解释:
假设您正在编写一个用于批准个人贷款的模块,并且在执行此操作之前,您想验证个人信息,那么按照代码明智的方式,我们可以将情况描述为:
public class LoanApprovalHandler
{
public void approveLoan(PersonalValidator validator)
{
if ( validator.isValid())
{
//Process the loan.
}
}
}
public class PersonalLoanValidator
{
public boolean isValid()
{
//Validation logic
}
}
到目前为止,一切都很好。 大家都知道,要求从来都不是相同的,现在批准汽车贷款,消费品贷款以及其他什么都不是。 因此,解决此要求的一种方法是:
public class LoanApprovalHandler
{
public void approvePersonalLoan (PersonalLoanValidator validator)
{
if ( validator.isValid())
{
//Process the loan.
}
}
public void approveVehicleLoan (VehicleLoanValidator validator )
{
if ( validator.isValid())
{
//Process the loan.
}
}
// Method for approving other loans.
}
public class PersonalLoanValidator
{
public boolean isValid()
{
//Validation logic
}
}
public class VehicleLoanValidator
{
public boolean isValid()
{
//Validation logic
}
}
我们已经编辑了现有的类别以适应新的要求-在此过程中,我们最终更改了现有方法的名称,并为不同类型的贷款批准添加了新方法。 这显然违反了OCP。 让我们尝试以另一种方式实现需求:
/**
* Abstract Validator class
* Extended to add different
* validators for different loan type
*/
public abstract class Validator
{
public boolean isValid();
}
/**
* Personal loan validator
*/
public class PersonalLoanValidator
extends Validator
{
public boolean isValid()
{
//Validation logic.
}
}
/*
* Similarly any new type of validation can
* be accommodated by creating a new subclass
* of Validator
*/
现在,使用上述验证器,我们可以编写一个LoanApprovalHandler来使用Validator抽象。
public class LoanApprovalHandler
{
public void approveLoan(Validator validator)
{
if ( validator.isValid())
{
//Process the loan.
}
}
}
因此,为了适应任何类型的贷款验证器,我们只需要创建Validator的子类,然后将其传递给approveLoan方法即可。 这样,该类关闭以进行修改,而打开以进行扩展。
另一个例子:
我在考虑另一个可以使用OCP原理的假设情况。 情况是这样的:“我们维护一个学生名单,包括他们的标记,唯一的标识(uid)以及姓名。 然后,我们提供一个选项,以uid-percentage名称值对的形式获取百分比。”
class Student
{
String name;
double percentage;
int uid;
public Student(String name, double percentage, int uid)
{
this.name = name;
this.percentage = percentage;
this.uid = uid;
}
}
我们将学生名单收集到一个通用班级中:
class StudentBatch {
private List<Student> studentList;
public StudentBatch() {
studentList = new ArrayList<Student>();
}
public void getSutdentMarkMap(Hashtable<Integer, Double> studentMarkMap) {
if (studentMarkMap == null) {
//Error
} else {
for (Student student : studentList) {
studentMarkMap.put(student.uid, student.percentage);
}
}
}
/**
* @param studentList the studentList to set
*/
public void setStudentList(List<Student> studentList) {
this.studentList = studentList;
}
}
假设我们需要按插入顺序维护Map中元素的顺序,因此我们必须编写一个新方法来按插入顺序获取地图,为此,我们将使用LinkedHashMap。 相反,如果方法getStudentMarkMap()依赖于Map接口而不是Hashtable具体实现,则可以避免更改StudentBatch类,而传入LinkedHashMap实例。
public void getSutdentMarkMap(Map<Integer, Double> studentMarkMap) {
if (studentMarkMap == null) {
//Error
} else {
for (Student student : studentList) {
studentMarkMap.put(student.uid, student.percentage);
}
}
}
PS:我知道Hashtable是一个过时的集合,不鼓励使用。 但是我认为这将为OCP原理提供另一个有用的例子。
使代码更接近确认OCP的一些方法:
将所有成员变量设为私有,以便代码的其他部分通过方法(获取程序)而非直接访问它们。
避免在运行时进行类型转换-这使代码易碎且依赖于所考虑的类,这意味着任何新类都可能需要编辑该方法以适应新类的类型转换。
Robert Martin在OCP上写的非常好的文章 。
参考:我们的JCG合作伙伴 Mohamed Sanaulla在“ Experiences Unlimited”博客中提供的 SOLID-开放封闭原则 。
翻译自: https://www.javacodegeeks.com/2011/11/solid-open-closed-principle.html