设计模式(Design pattern)
设计模式(Design pattern)是一套被反复使用、多数人知晓的、经过分类编目的、代码设计经验的总结。使用设计模式是为了可重用代码、让代码更容易被他人理解、保证代码可靠性。
设计原则
为什么要提倡“Design Pattern呢?根本原因是为了代码复用,增加可维护性。那么怎么才能实现代码复用呢?
设计模式的六大原则
-
开闭原则(Open Close Principle) 开闭原则就是说对扩展开放,对修改关闭。在程序需要进行拓展的时候,不能去修改原有的代码,实现一个热插拔的效果,模块应尽量在不修改原(是“原”,指原来的代码)代码的情况下进行扩展。 在面向对象设计中,不允许更改的是系统的抽象层,而允许扩展的是系统的实现层。换言之,定义一个一劳永逸的抽象设计层,允许尽可能多的行为在实现层被实现。
interface IReader{ public String getContent(); } class Newspaper implements IReader { public String getContent(){ eturn "林书豪17+9助尼克斯击败老鹰……"; } } class Book implements IReader{ public String getContent(){ return "很久很久以前有一个阿拉伯的故事……"; } } class Mother{ public void narrate(IReader reader){ System.out.println("妈妈开始讲故事"); System.out.println(reader.getContent()); } } public class Client{ public static void main(String[] args){ Mother mother = new Mother(); mother.narrate(new Book()); mother.narrate(new Newspaper()); } }
这样修改后,无论以后怎样扩展Client类,都不需要再修改Mother类了。
-
里氏代换原则(Liskov Substitution Principle) 任何基类可以出现的地方,子类一定可以出现。 LSP是继承复用的基石,只有当衍生类可以替换掉基类,软件单位的功能不受到影响时,基类才能真正被复用,而衍生类也能够在基类的基础上增加新的行为。 里氏代换原则是对“开-闭”原则的补充。实现“开-闭”原则的关键步骤就是抽象化。而基类与子类的继承关系就是抽象化的具体实现,所以里氏代换原则是对实现抽象化的具体步骤的规范。
如果调用的是父类的话,那么换成子类也完全可以运行。 IReader reader = new Book(); System.out.println(reader.getContent()); Book reader = new Book(); System.out.println(reader.getContent());
-
依赖倒转原则(Dependence Inversion Principle) 高层次的模块不应该依赖于低层次的模块,他们都应该依赖于抽象。 抽象不应该依赖于具体实现,具体实现应该依赖于抽象,针对对接口编程,依赖于抽象而不依赖于具体。
public class HondaCar{ public void Run(){ Console.WriteLine("本田开始启动了"); } public void Turn(){ Console.WriteLine("本田开始转弯了"); } public void Stop(){ Console.WriteLine("本田开始停车了"); } } public class FordCar{ publicvoidRun(){ Console.WriteLine("福特开始启动了"); } publicvoidTurn(){ Console.WriteLine("福特开始转弯了"); } publicvoidStop(){ Console.WriteLine("福特开始停车了"); } } public class AutoSystem{ public enum CarType{ Ford,Honda }; private HondaCar hcar=new HondaCar(); private FordCar fcar=new FordCar(); private CarType type; public AutoSystem(CarType type){ this.type=type; } private void RunCar(){ if(type==CarType.Ford){ fcar.Run(); } else { hcar.Run(); } } private void TurnCar(){ if(type==CarType.Ford){ fcar.Turn(); } else { hcar.Turn(); } } private void StopCar(){ if(type==CarType.Ford){ fcar.Stop(); } else { hcar.Stop(); } } } 这会给系统增加新的相互依赖。随着时间的推移,越来越多的车种必须加入到AutoSystem中,这个“AutoSystem”模块将会被if/else语句弄得很乱, 而且依赖于很多的低层模块,只要低层模块发生变动,AutoSystem就必须跟着变动, public interface ICar { void Run(); void Turn(); void Stop(); } public class AutoSystem { private ICar icar; public AutoSystem(ICar icar) { this.icar=icar; } private void RunCar() { icar.Run(); } private void TurnCar() { icar.Turn(); } private void StopCar() { icar.Stop(); } } 现在AutoSystem系统依赖于ICar 这个抽象,而与具体的实现细节HondaCar、FordCar、BmwCar无关, 所以实现细节的变化不会影响AutoSystem。对于实现细节只要实现ICar 即可,即实现细节依赖于ICar 抽象。
-
接口隔离原则(Interface Segregation Principle) 使用多个专门的接口比使用单一的总接口要好。 一个类对另外一个类的依赖性应当是建立在最小的接口上的。 一个接口代表一个角色,不应当将不同的角色都交给一个接口。没有关系的接口合并在一起,形成一个臃肿的大接口,这是对角色和接口的污染。 不要强迫客户使用它们不用的方法,如果强迫用户使用它们不使用的方法,那么这些客户就会面临由于这些不使用的方法的改变所带来的改变。
interface IOrderForPortal{ String getOrder(); } interface IOrderForOtherSys{ String insertOrder(); String getOrder(); } interface IOrderForAdmin{ //extendsIOrderForPortal,IOrderForOtherSys String deleteOrder(); String updateOrder(); String insertOrder(); String getOrder(); } class Order implements IOrderForPortal,IOrderForOtherSys,IOrderForAdmin{ private Order(){ } //返回给Portal public static IOrderForPortal getOrderForPortal(){ return (IOrderForPortal)new Order(); } //返回给OtherSys public static IOrderForOtherSys getOrderForOtherSys(){ return (IOrderForOtherSys)newOrder(); } //返回给Admin public static IOrderForAdmin getOrderForAdmin(){ return (IOrderForAdmin)new Order(); } //--下面是接口方法的实现.只是返回了一个String用于演示 public String getOrder(){ return "implemented getOrder"; } public String insertOrder(){ return "implementedinsertOrder"; } public String updateOrder(){ return "implementedupdateOrder"; } public String deleteOrder(){ return "implementeddeleteOrder"; } } public class TestCreateLimit{ public static void main(String[] args){ IOrderForPortal orderForPortal =Order.getOrderForPortal(); IOrderForOtherSys orderForOtherSys =Order.getOrderForOtherSys(); IOrderForAdmin orderForAdmin = Order.getOrderForAdmin(); System.out.println("Portal门户调用方法:"+orderForPortal.getOrder()); System.out.println("OtherSys外部系统调用方法:"+orderForOtherSys.insertOrder()); System.out.println("Admin管理后台调用方法:"+orderForAdmin.getOrder()+";" +orderForAdmin.insertOrder()+";"+orderForAdmin.updateOrder()+";" +orderForAdmin.deleteOrder()); } } 这样就能很好的满足接口隔离原则了,调用者只能访问它自己的方法,不能访问到不应该访问的方法.
-
迪米特法则(最少知道原则)(Demeter Principle) 一个实体应当尽量少的与其他实体之间发生相互作用,使得系统功能模块相对独立。
-
合成复用原则(Composite Reuse Principle) 量使用合成/聚合的方式,而不是使用继承。
设计模式的分类
- 创建型模式,共五种:工厂方法模式、抽象工厂模式、单例模式、建造者模式、原型模式。
- 结构型模式,共七种:适配器模式、装饰器模式、代理模式、外观模式、桥接模式、组合模式、享元模式。
- 行为型模式,共十一种:策略模式、模板方法模式、观察者模式、迭代子模式、责任链模式、命令模式、备忘录模式、状态模式、访问者模式、中介者模式、解释器模式。