设计模式之工厂模式和单例模式

/ 0评 / 0

    在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语言当中,单例模式是这样定义的:一个类有且只有一个实例,并且自行实例化向整个系统提供,在线程部分学习到了锁机制,这样可以利用锁机制来实现。由于这种特殊的模式单例模式的优缺点都是十分明显的 :

优点:

一、实例控制
单例模式会阻止其他对象实例化其自己的单例对象的副本,从而确保所有对象都访问唯一实例。
二、灵活性

因为类控制了实例化过程,所以类可以灵活更改实例化过程。

缺点:

一、开销
虽然数量很少,但如果每次对象请求引用时都要检查是否存在类的实例,将仍然需要一些开销。可以通过使用静态初始化解决此问题。
二、可能的开发混淆
使用单例对象(尤其在类库中定义的对象)时,开发人员必须记住自己不能使用new关键字实例化对象。因为可能无法访问库源代码,因此应用程序开发人员可能会意外发现自己无法直接实例化此类。
三、对象生存期

不能解决删除单个对象的问题。在提供内存管理的语言中(例如基于.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;
	}
}

    也可以使用枚举来实现单例模式,可以有效防止序列化对单例的影响。

    暂时先介绍这两种,其实还是在看重单利模式的设计 思想,其中牵扯多线程和序列化问题值得注意,而其他设计模式以后会陆续写入。

发表回复

您的电子邮箱地址不会被公开。 必填项已用*标注