一、设计模式概述
设计模式是程序员在面对同类软件工程设计问题所总结出来的有用的经验,模式不是代码,而是某类问题的通用解决方案,设计模式代表了最佳的实践。这些解决方案是众多软件开发人员经过相当长的一段时间的试验和错误总结出来的。
设计模式的本质是提高软件的维护性,通用性和扩展性,并降低软件的复杂度,设计模式并不局限于某种语言,Java、PHP、C++都有设计模式。
二、设计模式的目的
编写软件过程中,程序员面临着来自耦合性,内聚性以及可维护性,可扩展性,重用性,灵活性等多方面的挑战,设计模式是为了让程序具有更好的代码重用性、可读性、可靠性、可扩展性,使程序呈现高内聚,低耦合的特性。
三、设计模式的七大原则
1.单一职责原则
一个类只负责一个功能领域中的相应职责,也可以定义为:一个类应该只有一个发生变化的原因。
也就是说:一个类不能太"累",在一个系统中,如果一个类(大到模块,小到方法)承担的职责越多,那么它被复用的可能性就越小,而且耦合度越高,如果当其中一个职责发生改变时,可能会影响到其他职责,所以我们在设计开发的时候应该讲这些职责进行分离,将不同的职责封装在不同的类中。
举例说明:
方式一:不遵循单一职责原则
//交通工具类
class Vehicle{
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
/**
* 操作的类型
*/
enum OperateEnum {
RoadVehicle,
AirVehicle;
}
class VehicleServiceImpl{
//不符合单一职责原则:需将该方法拆分为陆地和空中两种方法
public void getVehicleInfo(OperateEnum type, Vehicle vehicle) {
if (type == OperateEnum.RoadVehicle) {
System.out.println(vehicle.getName() + "正在陆地上行驶!");
} else if(type == OperateEnum.AirVehicle) {
System.out.println(vehicle.getName() + "正在空中飞行!");
}
}
}
方式二:遵循单一职责原则
//交通工具类
class Vehicle{
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
class VehicleServiceImpl{
public void getRoadVehicleInfo(Vehicle vehicle) {
System.out.println(vehicle.getName() + "正在陆地上行驶!");
}
public void getAirVehicleInfo(Vehicle vehicle) {
System.out.println(vehicle.getName() + "正在空中飞行!");
}
}
第一种实现是根据操作类型进行区分,不同类型执行不同的逻辑,把陆地和空中这两件事耦合在一起了。容易发生发生错误。
第二种实现是我们推荐的实现方式。把陆地和空中逻辑分开,各自执行各自的职责互不干扰。
2.接口隔离原则
客户端不应该依赖它不需要的接口,即一个类对另一个类的依赖应该建立在最小接口上。也就是说使用多个专门的接口,而不使用单一的总接口。当一个接口太大时,我们需要将它分割成一些细小的接口,使用该接口的客户端只需知道与之相关的方法即可。
举例说明:
按照实际应用来说,Admin和Info只需要自己需要的方法即可,但由于接口的粒度太大,承担的责任太多,所以类Admin和Info必须去实现他们不需要的方法,这种情况就违背了接口隔离原则。
解决办法:只需要将接口拆分为GetUser和GetInfo两个接口即可
3.依赖倒置原则
依赖倒转原则(Dependence Inversion Principle)是指:高层模块不应该依赖低层模块,二者都应该依赖其抽象;抽象不应该依赖细节,细节应该依赖于抽象;依赖倒转原则的中心思想是面向接口编程。
相对于细节的多变性,抽象的东西要稳定的多。以抽象为基础搭建的构架比以细节为基础的构架要稳定得多。使用抽象的目的就是制定好规范,而不涉及任何具体的操作,把展现细节的任务交给具体的实现类去做。
举个例子:
如上图所示,User可接收来自Email、QQ、WeChat等多个渠道的信息,在User类中有三个重载的方法receive分别接收不同渠道的信息,如果通过这样的方式实现,那么当我们增加一个新的渠道时,就需要在User中添加一个对应的方法,信息的渠道有无数个,则我们需要增加的方法就有无数个,这种方式无疑是不合理的,我们可以做如下改进。