首先在介绍类的规范的时候,必须介绍下SOLID设计原则。在我们实际开发过程中,需要把SOLID作为一个整体,而不是单独看单个原则。
类或模块应有且只有一条加以修改的理由,系统应该有许多短小的类而不是少量巨大的类组成。每个小类封装一个职责,并与少数其他类一起协同达到期望的系统行为。
// 下面实例用户的属性和行为没有分离,应将其拆分成两个接口
public interface IUserInfo {
Long getUserId();
void setUserId(Long userId);
String getName();
void setName(String name);
String getPassword();
void setPassword(String password);
boolean changePassword(String oldPassword);
boolean deleteUser();
boolean addRoleId(Long roleId);
}
// 拆分1:负责用户的属性
public interface IUserBO {
Long getUserId();
void setUserId(Long userId);
String getName();
void setName(String name);
String getPassword();
void setPassword(String password);
}
// 拆分2:负责用户的行为
public interface IUserService {
boolean changePassword(IUserBO userInfo, String oldPassword);
boolean deleteUser(IUserBO userInfo);
boolean addRoleId(IUserBO userInfo, Long roleId);
}
类应该对扩展开发,对修改封闭。通过增加代码来扩展功能,而不是修改已经存在的代码。怎么来实现了?就是抽象,把已有的业务功能抽象成接口,对于修改的内容通过多态来实现扩展。这个原则是写代码里面我个人认为最重要的,下面我举两个例子。
// 下面代码有两种发消息方式,如果后面又增加一种微信的方式,要修改sendMessage类增加sendByWeChat()方法,还要修改调用方逻辑。
public class SendMessage() {
public boolean sendBySMS(String address, String content) {
}
public boolean sendByEmail(String address, String title, String content) {
}
}
// 修改后:抽象一个发消息的接口,让发SMS和Email实现这个接口,增加Wechat只需新增实现就行,这样就不需要已有的接口定义和实现类了
public interface SendMessage() {
boolean sendMessage(Message message);
}
里式替换原则说的是派生类(之类)对象能够替换其基类(父类)对象被使用。之类本来就可以替换父类,为什么还要里式替换原则了?这里强调的不是编译错误,而是程序运行的正确性。
public class Rectangle {
double width;
double height;
public double area() {
return width * height;
}
}
public class Square extends Rectangle {
public void setWidth(double width) {
this.width = width;
this.height = width;
}
public void setHeight(double height) {
this.height = width;
this.width = width;
}
}
public void testArea(Rectangle r) {
r.setWidth(5);
r.setHeight(4);
// 如果r是一个正方形,则面积为16,而不是期望的20,显然结果不对。
assert(r.area() == 20);
}
接口隔离原则含义是建立单一接口,不要建立庞大臃肿的接口,尽量细化接口,接口中的方法尽量少。在程序设计中,依赖几个专用的接口要比依赖一个综合的接口更灵活。接口之所以存在是为了解耦。开发者经常有个错误的认知,以为是实现类需要接口。其实是消费者需要接口,实现类只是提供服务,因此应该有消费者(客户端)来定义接口。
// 砖头可以被工人用来盖房子,也可以被用来正当防卫
public class Brick {
private int length;
private int width;
private int height;
private int weight;
public void build() {
// 工人盖房
}
public void defense() {
// 正当防卫
}
}
// 提取以下接口,普通大众需要的是正当防卫,并不需要盖房子。当普通大众被迫依赖了自己不需要的接口方法时,就违反接口隔离原则了。
public interface BrickInterface {
void buildHouse();
void defense();
}
// 站在消费这角度,抽象出接口
public interface BuildHouse {
void build();
}
public interface StrickCompetence {
void defense();
}
// 普通人只需正当防卫
public class Person implements BuildHouse {
}
// 工人建造房子
public class Worker implements StrickCompetence {
}
高层模块不应该依赖低层模块,二者都应该依赖其抽象。抽象不依赖于细节,细节应该依赖于抽象。依赖倒置原则的核心思想面向接口编程。
// 妈妈拿着书给孩子讲故事
public class Book {
public String getContent() {
return "从前,山里有个庙,庙里有两个和尚...";
}
}
public class Mother {
public void narrate(Book book) {
System.out.println("妈妈开始讲故事");
System.out.println(book.getContent());
}
}
// 问题:万一哪天书要换成报纸、杂志、网页了?Mother和Book强耦合在一起,这个时候还需要修改Mother。
// 修改:引入抽象的接口IReader,Mother和IReader发生依赖关系。
public interface IReader {
String getContent();
}
public class Mother {
public void narrate(IReader reader) {
System.out.println("妈妈开始讲故事");
System.out.println(reader.getContent());
}
}
public class Book implements IReader {
public String getContent() {
return "从前,山里有个庙,庙里有两个和尚...";
}
}
public class Newspaper implements IReader {
public String getContent() {
return "湖人总冠军...";
}
}
实际编程注意以下三点:
衡量类的大小,通过计算职责,类的名称应当描述其职责,如果一个类职责过多,表明这个类不够短小。要保持类“短小”应该满足单一职责原则和高内聚。
内聚性又称块内联系,指一个模块内部各个元素彼此结合的紧密程度的度量。类应该只有少量实体变量,类中的每个方法都应该操作一个或多个这种变量。方法操作的变量越多,就越黏聚到类上。保持内聚性会得到很多短小的类,
// 一个高内聚的代码示例,只有size()方法没用到两个变量,其他都用到了。
public class Stack {
private int topOfStack = 0;
List<Integer> elements = new LinkedList<>();
public int size() {
return topOfStack;
}
public void push(int element) {
topOfStack++;
elements.add(element);
}
public Integer pop() {
if (topOfStack == 0) {
return null;
}
Integer element = elements.get(--topOfStack);
elements.remove(topOfStack);
return element;
}
}
这里说到高类聚,随便提下低耦合。耦合性又称块间联系,指软件系统结构中各模块间相互联系紧密程度的一种度量。举例:假设现在你程序运行的非常好,你修改其中一个类,其他20个类、接口都需要做修改,这就是高耦合的后果。
对于多数系统,会一直进行修改,而每次修改都会伴随风险和产生bug,所以我们降低修改的风险就显得尤为重要。这里要提到两个准则OCP和DIP。
原文:https://www.cnblogs.com/wudiffs/p/11361927.html