设计模式的六大原则
一、设计模式的概念及作用
设计模式(Design pattern)是一套被反复使用、多数人知晓的、经过分类编目的、代码设计经验的总结。使用设计模式是为了可重用代码、让代码更容易被他人理解、保证代码可靠性。设计模式使代码编制真正工程化,设计模式是软件工程的基石,如同大厦的一块块砖石一样。
二、六大原则
1.单一职责原则(Single Responsibility Principle,简称SRP)
1) 概念:一个类只负责一项职责。
2) 举例说明:假设有一个接口,如下:
1 // 用户接口 2 public interface IUser{ 3 // 连接数据库方法 4 public Connection getConnection(); 5 // 查询用户 6 public User qryUser(User user); 7 // 增加用户 8 public int addUser(User user); 9 }
当操作数据库的信息改变的时候,需要修改大量的代码,所以,可以将操作数据库的方法抽离出来,将上面的用户接口改为:
1 // 数据库操作类 2 public class DBUtil{ 3 // 连接数据库方法 4 public static Connection getConnection(){....} 5 } 6 7 // 用户接口 8 public interface IUser{ 9 // 查询用户 10 public User qryUser(User user); 11 // 增加用户 12 public int addUser(User user); 13 } 14 15 // 用户实现类 16 public class UserImpl{ 17 Connection connection = null; 18 // 查询用户 19 public User qryUser(User user){ 20 connection = DBUtil.getConnection(); 21 .... 22 } 23 // 增加用户 24 public int addUser(User user){ 25 connection = DBUtil.getConnection(); 26 .... 27 } 28 }
即,用户接口中只操作用户的基本信息,不操作数据库。若要需要使用数据库操作,将数据库操作抽离出来,降低代码的耦合性。
3) 优点:类的复杂度降低、可读性提高、可维护性提高、扩展性提高、降低了变更引起的风险。
2.里氏替换原则(Liskov Substitution Principle,简称LSP)
之所以叫里氏替换原则1988年,是因为该原则是由麻省理工学院的一位姓里的女士(Barbara Liskov)提出来的。
1) 概念:所有引用父类的地方必须能 透明使用子类,反过来 不成立。
2) 举例说明:
喜欢动物 = 喜欢狗,因为动物中 包含狗,等式是成立的。
喜欢狗 != 喜欢动物。
class Animal{}
class Dog extends Animal{}
3) 优点:增强程序的健壮性,即使增加了子类,原有的子类还可以继续运行。
3.依赖倒置原则(Dependence Inversion Principle,简称DIP)
1) 概念:依赖倒置原则的本质就是通过抽象(接口或抽象类)使个各类或模块的实现彼此独立,互不影响,实现模块间的松耦合。
2)举例说明:假设有一个CD唱片,CD唱片的播放 需要 CD播放机,即:
1 // CD 2 class CDRom{ 3 public void play(){ 4 System.out.println("play CDRom"); 5 } 6 } 7 8 // CD播放机 9 class Player{ 10 public void start(CDRom cd){ 11 System.out.println("CD playing ..."); 12 cd.play(); 13 } 14 } 15 16 // 测试方法 17 public class Main{ 18 public static void main(Stirng[] args){ 19 Player player = new Player(); 20 CDRom cd = new CDRom(); 21 player.start(cd); 22 } 23 }
随着科技的发达,DVD出现了,这时候就需要DVD播放机了,如下:
1 // DVD 2 class DVDRom{ 3 public void play(){ 4 System.out.println("play DVDRom"); 5 } 6 } 7 8 // DVD播放器 9 class Player{ 10 public void start(CDRom cd){ 11 System.out.println("DVD playing ..."); 12 cd.play(); 13 } 14 }
又随着科技的发达,MP3、MP4等问世,这时候我们又需要定义更多的类,这样子会很繁琐,所以,可以定义一个上层接口,让下层的类去实现,将上面的代码 改为 如下:
1 // 媒体接口 2 inteferce Media{ // cd,dvd,mp3,mp4.mp5... 3 public void play(); 4 } 5 6 // DVD,并实现媒体接口 7 class DVDRom impl Media{ 8 public void play(){ 9 System.out.println("play DVDRom"); 10 } 11 } 12 13 // CD,并实现媒体接口 14 class CDRom impl Media{ 15 public void play(){ 16 System.out.println("play CDRom"); 17 } 18 } 19 20 // 通用播放机 21 class Player{ 22 public void start(Media media){ 23 System.out.println("playing ..."); 24 media.play(); 25 } 26 } 27 28 // 测试方法 29 public class Main{ 30 public static void main(Stirng[] args){ 31 Player player = new Player(); 32 media cd = new CDRom(); 33 34 media dvd = new DVDRom(); 35 player.start(dvd); 36 } 37 }
3) 优点:在小型项目中很难体现出来。但在大中型项目中可以减少需求变化引起的工作量,使并行开发更友好。
4.接口隔离原则(Interface Segregation Principle,简称ISP)
1.概念:类间的依赖关系应该建立在最小的接口上。
可以理解为:建立单一接口,不要建立庞大臃肿的接口,尽量细化接口,接口中的方法尽量少。也就是说,我们要为各个类建立专用的接口,而不要试图去建立一个很庞大的接口供所有依赖它的类去调用。
一句话概括:一个接口中不要什么事情都去做,其实什么事情都做不好。
2.举例说明:
1 // 灯接口 2 interface light{ 3 // 开灯方法 4 on(); 5 // 关灯方法 6 off(); 7 // 维修方法 8 repare(); 9 // 开电视方法 10 turnOnTV(); 11 }
上面的灯接口中,既有灯的方法,又有工作人员的接口,又有电视的接口,这样 一个接口就会显得很臃肿,很庞大。
运用接口隔离原则之后,将接口细化,分散为多个接口,可以预防外来变更的扩散。如下:
1 // 灯接口 2 interface light{ 3 // 开灯方法 4 on(); 5 // 关灯方法 6 off(); 7 } 8 9 // 电视接口 10 intefece tv{ 11 // 开电视接口 12 on(); 13 // 关电视接口 14 off(); 15 } 16 17 // 工作人员 18 intefece worker{ 19 // 维修 20 repaire(); 21 }
3.优点:通过分散定义多个接口,可以预防外来变更的扩散,提高系统的灵活性和可维护性。
5.迪米特法则(Law of Demeter,简称LoD)
1.概念:类间解耦。
2.问题由来:类与类之间的关系越密切,耦合度越大,当一个类发生改变时,对另一个类的影响也越大。
3.注意点:迪米特法则的初衷是降低类之间的耦合,由于每个类都减少了不必要的依赖,因此的确可以降低耦合关系。但是凡事都有度,虽然可以避免与非直接的类通信,但是要通信,必然会通过一个“中介”来发生联系。过分的使用迪米特原则,会产生大量这样的中介和传递类,导致系统复杂度变大。所以在采用迪米特法则时要反复权衡,既做到结构清晰,又要高内聚低耦合。
6.开闭原则(Open Close Principle,简称OCP)
1). 思想:尽量通过扩展软件实体来解决需求变化,而不是通过修改已有的代码来完成变化。
2). 开:对扩展开放
关:对修改关闭
总结:单一职责原则告诉我们实现类要职责单一;
里氏替换原则告诉我们不要破坏继承体系;
依赖倒置原则告诉我们要面向接口编程;
接口隔离原则告诉我们在设计接口的时候要精简单一;
迪米特法则告诉我们要降低耦合;
开闭原则是总纲,他告诉我们要对扩展开放,对修改关闭。