在Java编程当中往往让编码无从下手的地方便是如何确定方向,选择合适的方法都会让工作的效率极大的提高,不光在Java,在所有面向对象语言当中都有一些固定的方法去解决问题,经过一段 时间的沉淀和 改变,这些设计模式成为编程出发点。
在一般的情况下设计模型分为创建型 结构型 和行为型。而这三大类再次细分之后又分为如下图
而以上的二十三种是面向对象当中所有的设计模式,这里针对一些常用的设计模式进行简述,详细请参考《设计模式》或者百度。
工厂模式
工厂模式主要是为创建对象提供过渡接口,以便将创建对象的具体过程屏蔽隔离起来。工厂模式可以细分为:
1、简单工厂模式 :不利于 生产系列产品
2、工厂方法模式 :称为多边形性工厂
3、抽象工厂模式 :生产产品族,不利于产生新的产品
1、简单工厂:
又称为静态工厂方法模式 核心是一个具体的类
优点:如果客户端需要某种产品,只要向工厂类发送请求,由该类负责所有产品的生产
缺点:如果新增具体产品的时候,需要改动工厂类的代码。
2、工厂方法模式
工厂方法模式是简单工厂模式的进一步抽象化和推广,工厂方法里不再只由一个工厂类决定,那一个产品类应当被实例化,这个决定被交给 抽象类的子类去做 核心是一个抽象工厂类。
优点:解决简单工厂模式有新产品加入时,需要更改原有工厂类的问题,本模式党章一旦有新产品加入只需要创建与之对应的具体工厂类。
缺点:系统中存在大量的具体工厂类,每个工厂类只能支撑一个子产品
3、抽象工厂模式:
解决工厂方法模式缺陷。
如:
package xin.factory; import java.io.BufferedReader; import java.io.FileInputStream; import java.io.InputStreamReader; import java.util.Properties; abstract class Factory { public abstract OnePlus one(); } /* * class Get32G extends Factory { public OnePlus one() { return new T32G(); } } * * class Get64G extends Factory { public OnePlus one() { return new T64G(); } } * * class Get128G extends Factory { public OnePlus one() { return new T128G(); } * } */ public class AbstractFactory { public static void main(String[] args) { String name = ""; try (BufferedReader br = new BufferedReader(new InputStreamReader( new FileInputStream("src/xin/factory/set.txt")))) { name = br.readLine(); } catch (Exception e) { e.printStackTrace(); } try { Properties sks = new Properties(); sks.load(new FileInputStream("src/bin.properties")); String key = sks.getProperty(name); OnePlus tk = (OnePlus) (Class.forName(key).newInstance()); tk.Virtual(); } catch (Exception e) { e.printStackTrace(); } } }
package xin.factory; abstract class ProSmart{} abstract class ProVovi{} abstract class AbstractPhone{ public abstract ProSmart SmartT1(); public abstract ProVovi vovi(); public abstract OnePlus one(); } public class Product {}
package xin.factory; public abstract class OnePlus { public abstract void Virtual(); } class T32G extends OnePlus{ public void Virtual(){ System.out.println("This is 32G!"); } } class T64G extends OnePlus{ public void Virtual(){ System.out.println("This is 64G!"); } } class T128G extends OnePlus{ public void Virtual(){ System.out.println("This is 128G!"); } }
单例模式
说起来比较特殊,它是一种常用的软件设计模式,几乎任何一门面向对象语言都有这个模式的实现方法,在它的核心结构当中只包含了一个被称为单例的特殊类,你通过这个类只能创建一个实例,在实际生活当中这种唯一性是有很大的用途。
在Java语言当中,单例模式是这样定义的:一个类有且只有一个实例,并且自行实例化向整个系统提供,在线程部分学习到了锁机制,这样可以利用锁机制来实现。由于这种特殊的模式单例模式的优缺点都是十分明显的 :
优点:
因为类控制了实例化过程,所以类可以灵活更改实例化过程。
缺点:
不能解决删除单个对象的问题。在提供内存管理的语言中(例如基于.NET Framework的语言),只有单例类能够导致实例被取消分配,因为它包含对该实例的私有引用。在某些语言中(如 C++),其他类可以删除对象实例,但这样会导致单例类中出现悬浮引用。
这里借用 菜鸟教程(链接:http://www.runoob.com/design-pattern/singleton-pattern.html ) 的一个Demo来实现单利模式:
根据上面的类图
public class SingleObject { // 创建 SingleObject 的一个对象 private static SingleObject instance = new SingleObject(); // 让构造函数为 private,这样该类就不会被实例化 private SingleObject() { } // 获取唯一可用的对象 public static SingleObject getInstance() { return instance; } public void showMessage() { System.out.println("Hello World!"); } }
public class SingletonPatternDemo { public static void main(String[] args) { //不合法的构造函数 //编译时错误:构造函数 SingleObject() 是不可见的 //SingleObject object = new SingleObject(); //获取唯一可用的对象 SingleObject object = SingleObject.getInstance(); //显示消息 object.showMessage(); } }
单利模式的几种实现方式:
懒汉式,线程安全
优点:第一次调用才初始化,避免内存浪费。
缺点:必须加锁 synchronized 才能保证单例,但加锁会影响效率。
getInstance() 的性能对应用程序不是很关键(该方法使用不太频繁)。
是否 Lazy 初始化:是
是否多线程安全:是
实现难度:易
描述:这种方式具备很好的 lazy loading,能够在多线程中很好的工作,但是,效率很低,99% 情况下不需要同步。
public class Singleton { private static Singleton instance; private Singleton() { } public static synchronized Singleton getInstance() { if (instance == null) { instance = new Singleton(); } return instance; } }
饿汉式
是否 Lazy 初始化:否
是否多线程安全:是
实现难度:易
描述:这种方式比较常用,但容易产生垃圾对象。
优点:没有加锁,执行效率会提高。
缺点:类加载时就初始化,浪费内存。
它基于 classloder 机制避免了多线程的同步问题,不过,instance 在类装载时就实例化,虽然导致类装载的原因有很多种,在单例模式中大多数都是调用 getInstance 方法, 但是也不能确定有其他的方式(或者其他的静态方法)导致类装载,这时候初始化 instance 显然没有达到 lazy loading 的效果。
public class Singleton { private static Singleton instance = new Singleton(); private Singleton() { } public static Singleton getInstance() { return instance; } }
双检锁/双重校验锁(DCL,即 double-checked locking)
JDK 版本:JDK1.5 起
是否 Lazy 初始化:是
是否多线程安全:是
实现难度:较复杂
描述:这种方式采用双锁机制,安全且在多线程情况下能保持高性能。
public class Singleton { private volatile static Singleton singleton; private Singleton() { } public static Singleton getSingleton() { if (singleton == null) { synchronized (Singleton.class) { if (singleton == null) { singleton = new Singleton(); } } } return singleton; } }
也可以使用枚举来实现单例模式,可以有效防止序列化对单例的影响。
暂时先介绍这两种,其实还是在看重单利模式的设计 思想,其中牵扯多线程和序列化问题值得注意,而其他设计模式以后会陆续写入。