这段时间学习了一下软件开发中的设计模式,这篇读书笔记就谈谈我对设计模式的理解。java
设计模式不是一套api,而是一种可复用的、通常性的解决方式,相似于之前谈过的MSF,其官方定义以下:设计模式(design pattern)是软件开发人员在软件开发过程当中面临的通常问题的解决方案。设计模式的提出自己是基于面向对象的语言的,没有了面向对象的继承与多态,全部设计模式都玩不转了。设计模式分为三大类,建立型、结构型、行为型,此次就主要谈谈建立型设计模式。程序员
首先是最多见的工厂模式,官方的说法是:定义一个建立对象的接口,让其子类本身决定实例化哪个工厂类,工厂模式使其建立过程延迟到子类进行。这句话真的很难懂,因此不如举个例子,到汽车厂提车,不管宝马、奥迪仍是奥拓只要提就好了,没必要管具体的制造细节。这样的说法感受清晰了些,能够看出工厂模式提供了必定程度上的封装,但具体它要实现怎样的目的呢?放一段Java源码:设计模式
public interface Shape { void draw(); } public class Rectangle implements Shape { @Override public void draw() { System.out.println("Inside Rectangle::draw() method."); } } public class Square implements Shape { @Override public void draw() { System.out.println("Inside Square::draw() method."); } } public class Circle implements Shape { @Override public void draw() { System.out.println("Inside Circle::draw() method."); } } public class ShapeFactory { public Shape getShape(String shapeType){ if(shapeType == null){ return null; } if(shapeType.equalsIgnoreCase("CIRCLE")){ return new Circle(); } else if(shapeType.equalsIgnoreCase("RECTANGLE")){ return new Rectangle(); } else if(shapeType.equalsIgnoreCase("SQUARE")){ return new Square(); } return null; } }
这样一切都清晰了,用我本身的话说,工厂模式实现的是对一类产品族的封装。其实你们多少都用过工厂模式,当初学习C++虚基类以及Java接口的时候,确定尝试过经过一个抽象类实现各类相应的实体类,这个过程其实即便工厂模式的核心,即基于接口与实现技术,对于C++也能够说是虚基类与继承技术。要说工厂模式比咱们原来写的东西多了什么,就是最后的 ShapeFactory 类以及其 getShape 方法,我相信当初大部分人都不会使用这种写法,但仔细一下这种方式实现了对上层很是干净的封装,对于用户来讲不再须要想着new一个什么样的对象,须要的只是产生一个 ShapeFactory 对象,而后从中 getShape 获得想要的对象,即只要走进汽车工厂就能够取到各类各样的车。api
有句题外话,就是我在看工厂模式的过程当中忽然模糊了Java中虚基类与接口的区别,查了查才想起来虚基类的部分函数是已经实现了的,子类只需实现那些没有实现的类,而接口的函数所有都是虚函数,实现类必须实现其中所有的函数。安全
下面看看单例模式,这种模式要求该类本身负责建立本身,且需确保只有单个对象被建立。为了确保该类不会被实例化,有种骚操做就是把构造函数设为 private ,这样若是该类被 new 则编译器报错,这种操做真的是长见识。具体的单例模式代码还分为懒汉模式和饿汉模式。多线程
懒汉模式:ide
public class Singleton { private static Singleton instance; private Singleton (){} public static synchronized Singleton getInstance() { if (instance == null) { instance = new Singleton(); } return instance; } }
其中 synchronized 关键字是为了保证线程安全,即多线程访问时给对象上锁。从下能够看到饿汉模式不存在这种问题。函数
饿汉模式:性能
public class Singleton { private static Singleton instance = new Singleton(); private Singleton (){} public static Singleton getInstance() { return instance; }
这二者的区别就在于,懒汉模式的初始化在被调用时进行,而饿汉模式的初始化在类加载时就进行了,这带来的结果就是懒汉模式更节省内存,可是其自己存在线程不安全的问题,必须使用 sychronized 关键字,因此性能会比较低,通常在单例用的次数少且消耗资源大时使用。学习
单例模式这样就讲清楚了,可是带来的新的问题是类到底什么时候被初始化?我查了相关资料发现,JVM并无规定类什么时候被加载(加载到JVM方法区和堆区),但严格规定了什么时候被初始化,其中最多见的两种状况就是 new 一个类或者调用其静态方法(还包括读取、设置静态字段等状况),一旦出现上述状况类就必须被初始化,而饿汉模式中的static成员instance在类加载时被赋值,同时 new 了自身,因此该类在加载时就初始化,懒汉模式就能够等到被调用再初始化。
可见,这么短短两段代码中蕴藏着那么多知识,充分体现了第一次提出规范单例模式的程序员的智慧。
最后再谈谈原型模式。原型模式的目的是建立重复的对象,好比说,若是类的初始化须要不少资源,不如只保存一份相应的对象。从这个角度看,原型模式很像是单例模式的扩展,能够当作是一个产品族的单例集合。看看以下java代码:
public abstract class Shape implements Cloneable { private String id; protected String type; abstract void draw(); public String getType(){ return type; } public String getId() { return id; } public void setId(String id) { this.id = id; } public Object clone() { Object clone = null; try { clone = super.clone(); } catch (CloneNotSupportedException e) { e.printStackTrace(); } return clone; } } public class ShapeCache { private static Hashtable<String, Shape> shapeMap = new Hashtable<String, Shape>(); public static Shape getShape(String shapeId) { Shape cachedShape = shapeMap.get(shapeId); return (Shape) cachedShape.clone(); } public static void loadCache() { Circle circle = new Circle(); circle.setId("1"); shapeMap.put(circle.getId(),circle); Square square = new Square(); square.setId("2"); shapeMap.put(square.getId(),square); Rectangle rectangle = new Rectangle(); rectangle.setId("3"); shapeMap.put(rectangle.getId(),rectangle); } }
java中自带的 Cloneable 类能够很好地实现原型模式的目的。虽然上述代码有些工厂模式的感受,但其实原型模式的目的与工厂模式彻底不一样。可是,原型模式最大的用处之一就是和工厂模式结合,若是把上述代码中的形状改成工厂,具体的形状改成不一样的工厂,那么最后的 Cache 提供的就是不一样工厂的克隆,这很好地实现了工厂的单例性。
本文描述了工厂模式、单例模式、原型模式三种常见的建立型设计模式,下次再来讲说结构型设计模式。