面向对象设计原则
在看每一本讲述设计模式的书,都会提前讲到面向对象的设计原则,记得上这门课的时候老师也是提前讲了这个原则,当然当初没有好好听了,后来发现23中设计模式确实是遵循了这个原则,这样对软件的维护带来很多方便。好了不废话了
良好的面向对象设计需要遵循一些基本原则,如单一职责原则(SRP) 、开-闭原则(OCP)、里氏替换原则(LSP)、依赖倒置原则(DIP)、接口隔离原则(ISP)等。
一、单一职责原则(Single Responsibility Principle)
其含义是 对于一个类而言,应该仅有一个引起它变换的原因。我们在构造对象时,应将对象的不同职责分离制多个类中,从而确保引起该来类变化的原因只有一个。如下面的例子 Document类具有两个引起其变化的因素一个是content的改变,一个是print的改变:
private String content;
public String getContent() {
return content;
}
public void setContent(String content) {
this.content = content;
}
public void print(){
System.out.println("print document context to console!");
}
}
如果我们需要把打印的方式修改,比如需要将它传送至文件或者网络打印,print的内容还有重新修改,这样以来便违反了SRP原则。合理修改的方法是在Document类中将打印的方法放在另一个职责中,如IPrint接口,只在Document中调用IPrint接口的方法,打印方法修改仅仅是IPrint的实现类修改,并不会影响到Document类的修改:
iPrint.print();
}
private IPrint iPrint;
public IPrint getiPrint() {
return iPrint;
}
public void setiPrint(IPrint iPrint) {
this.iPrint = iPrint;
}
二、开-闭原则(Open for extension,Closed for modification)
其含义是:一个软件实体应当对扩展开放,对修改关闭 。我们在设计一个模块时,应当使这个模块可以在不被修改的前提下被扩展,也就说我们应该将可变性封装在对象里面。如下面的例子汽车类,有个发动机属性,如果要更改发动的类型将要去更改汽车类:
private String name;
private V4Eng eng;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public V4Eng getEng() {
return eng;
}
public void setEng(V4Eng eng) {
this.eng = eng;
}
}
如果我们将V4Eng换成V8Eng,则需要修改Car类,较好的修改方式是将可变性封装到一个IEng接口中,这样修改汽车引擎就可以不必修改Car类了。
三、里氏替换原则(Liskov Substitution Principle)
其含义是若对每个类S的对象O1,都存在一个T的对象O2,使得在所有针对T编写的程序P中,用O1替换O2后,程序P行为功能不能改变,则S是T的子类,通俗地讲就是子类必须可以替换其基类 。其应用体现在继承关系上,在实现继承时,子类必须能够替换掉它们的基类,才能保证在系统运行期间识别子类。下面的例子可能不是很合适:矩形有长和宽两个属性,正方形继承了矩形成为其子类,但是实际上正方形的特点和矩形不一样,因为它的宽和高不能独立变化,所有就会在编码过程某些情况下用正方形去替代矩形时就会出问题。
四、依赖倒置原则(Dependency Inversion Principle)
其含义是高层模块不应该依赖于底层模块,两者都应该依赖于抽象,抽象不应该依赖于具体实现,具体实现应该依赖于抽象。在模块编程中要依赖抽象编程,不要依赖于具体细节编程,即针对接口编程,不要针对具体实现编程。下面一个例子,显然在实际编程中我们应该使用第二种方式:
ArrayList<String> lista = new ArrayList<String>();
lista.add("one");
lista.add("two");
List<String> listb = new ArrayList<String>();
listb.add("first");
listb.add("second");
}
五、接口隔离原则(Interface Segregation Principle)
其含义是不要强迫客户依赖于他们不需要的犯法,应用接口将两者隔离。在编程中一个类对另外一个类的依赖性是应当是建立在最小的接口上的。客户需要哪些方法我们就提供哪些方法,不提供不需要的方法。将接口分离则接口实现就不能具有别的功能,这样同时也更安全。如下一个例子工厂类实现了生产和消费的接口,但是作为生产不具有消费功能,同时作为消费者也不具有生产功能:
public class Factory implements IProduce, IConsume{
System.out.println("produce");
}
public void consume(){
System.out.println("consume");
}
public static void main(String[] args) {
IConsume consume = new Factory();
consume.consume();
IProduce produce = new Factory();
produce.produce();
}
}