设计模式六大原则——接口隔离原则
概念
接口端不应该依赖它不需要的接口,一个类对另一个类的依赖应该建立在最小的接口上。
问题描述
当一个提供接口的类中对于它的子类来说不是最小的接口,那么它的子类在实现该类的时候就必须要实现一些自己不需要的功能。如此一来,整个系统就会变得臃肿难以维护。
问题由来
当类A通过接口I来依赖B,类C也通过接口I来依赖D,那么对于类A和类C来说,如果接口I不是最小接口,那么类B和类D就必须要实现他们不需要的方法。
解决问题
遵守接口隔离原则,将“胖大”接口I拆分为独立的几个接口,类A和类C分别与他们需要的接口类来建立依赖关系。这样他们依赖的类就不需要实现他们不需要的方法。
实例
场景:某高三学生需要进行一次模拟测试,由于文理科教学内容之别,那么他们考试内容也有区别。假如现在考试的内容有语文,数学,地理,物理这些科目。 作为文科生,他们只考语文,数学,地理;而作为理科生,他们要考语文,数学,物理。用C++来实现这个功能该怎么实现呢?
//没有采用接口隔离原则的实现方式
class IExamination
{
public:
virtual void Chinese() = 0;
virtual void Math() = 0;
virtual void Physics() = 0;
virtual void Geographic() = 0;
};
//文科生只考语文、数学、地理
class ArtsExamination : public IExamination
{
public:
virtual void Chinese()
{
cout << "Test Chinese" << endl;
}
virtual void Math()
{
cout << "Test Math" << endl;
}
virtual void Geographic()
{
cout << "Test Geographic" << endl;
}
//此时物理接口对于文科生没用,但是必须实现
virtual void Physics()
{
//空
}
};
//理科生只考语文、数学、物理
class ScienceExamination : public IExamination
{
public:
virtual void Chinese()
{
cout << "Test Chinese" << endl;
}
virtual void Math()
{
cout << "Test Math" << endl;
}
virtual void Physics()
{
cout << "Test Physics" << endl;
}
//此时物理接口对于文科生没用,但是必须实现
virtual void Geographic()
{
//空
}
};
如此实现的话显然是有问题的,为什么一个类里面会出现空函数这么尴尬的东西。如果现在文理科目不止这四科,增加了生物,历史等等,那是不是出现的空函数就更多了。这时候就需要使用接口隔离原则,让类之间的依赖建立在最小接口的原则上。
class IExamination
{
public:
virtual void Chinese() = 0;
virtual void Math() = 0;
};
class ArtsExamination : public IExamination
{
public:
virtual void Chinese()
{
cout << "Test Chinese" << endl;
}
virtual void Math()
{
cout << "Test Math" << endl;
}
//这儿添加地理这门科目
void Geographic()
{
cout << "Test Geographic" << endl;
}
};
//理科生只考语文、数学、物理
class ScienceExamination : public IExamination
{
public:
virtual void Chinese()
{
cout << "Test Chinese" << endl;
}
virtual void Math()
{
cout << "Test Math" << endl;
}
//这儿添加物理这门科学
void Physics()
{
cout << "Test Physics" << endl;
}
};
但是在使用接口隔离原则的时候,还是需要根据情况来控制接口的粒度,接口太小会引起系统中接口泛滥,不利于维护;太大则有违背了接口隔离规则,容易出现“胖大”接口。所以一般接口中只为被依赖的类提供定制的方法即可,不要让客户去实现他们不需要的方法。