单例模式和工厂模式

单例模式

整个类只能有一个已经预定好的实例,该类保证只有一个对象被创建,这里的一个对象指:不管创建多少个对象,都是相同的对象。

Java反射能够使用private类型的构造器构建实例,遇上反射什么单例模式都不单例了。

单例模式的特点:

  1. 构造方法为私有
  2. 持有自己类型的属性
  3. 对外提供获取单例的静态方法

饿汉式

在程序运行时直接创建单例,线程安全,全局只有一个初始就被实例化的单例,但是因为一开始就初始化,不利于内存利用

//饿汉式
public class Singleton1 {

	private static Singleton1 singleton = new Singleton1();

	private Singleton1() {
	}

	public static Singleton1 getInstance() {
		if (singleton == null) {
			return new Singleton1();
		}
		return singleton;
	}
}

懒汉式

好处是实现了对象的延迟加载,在需要的时候才会创建单例,但是线程不安全,多个线程访问时会出现多个单例。

//懒汉式
public class Singleton2 {

	private static Singleton2 singleton;

	private Singleton2() {}
	
	public static Singleton2 getInstance() {
		if (singleton == null) {
			return new Singleton2();
		}
		return singleton;
	}
}

在此有必要说明为什么懒汉式线程不安全,问题就处在下面的代码处:

当线程A运行到(1)处的代码,判定singleton==null的结果为true,准备创建singleton时,线程B获取到了CPU资源开始运行,线程B执行完了以上代码,得到一个singleton对象,但是线程A并不知道,线程A就会继续创建出多余的singleton。

双重加锁模式

保证线程安全。

//双重加锁
public class Singleton4 {

	private static volatile Singleton4 singleton;
	
	private Singleton4() {}
	
	public static Singleton4 getInstance() {
		//双重判断
		if (singleton==null) {
			synchronized (Singleton4.class) {
				if (singleton==null) {
					singleton = new Singleton4();
				}
			}
		}
		return singleton;
	}
}

静态内部类模式

把singleton的创建放在内部类中,这样当程序运行时,只有在调用getInstance()方法时才会调用内部类创建singleton,既保证了线程安全,又避免了饿汉式一开始就实例化单例。

//静态内部类单例模式
public class Singleton3 {

	private Singleton3() {}
	
	public static Singleton3 getInstance() {
		return Inner.INSTANCE;
	}
	
	//内部类
	private static class Inner{
		private static final Singleton3 INSTANCE = new Singleton3();
	}
}

工厂模式

工厂模式的作用就是解耦,在多个类实现了同一接口的情况下,解接口和实现类之间的耦合。

用户可以根据自己的需求,从工厂中拿走自己需要的产品。当工厂需要增加产品,只要修改工厂类即可,不需要修改客户端代码。

在创建类的实例时,

一个例子:Fruit接口,有Apple,Banana,Orange等实现类。

//水果接口
public interface Fruit {
	//得到一种水果
	public void get();
}
//苹果
class Apple implements Fruit{
	@Override
	public void get() {
		System.out.println("得到了一个苹果");
	}
}
//香蕉
class Banana implements Fruit{
	@Override
	public void get() {
		System.out.println("得到了一根香蕉");
	}
}
//橘子
class Orange implements Fruit{
	@Override
	public void get() {
		System.out.println("得到了一个橘子");
	}
}
//unknown
class Unknown implements Fruit{
	@Override
	public void get() {
		System.out.println("what the hell do you want from me!");
	}
}

简单工厂模式

SimpleFruitFactory.java:

public class SimpleFruitFactory {
	public static Fruit getFruit(String FruitName) {
		switch (FruitName) {
		case "Apple":
			return new Apple();
		case "Banana":
			return new Banana();
		case "Orange":
			return new Orange();
		default:
			return new Unknown();
		}
	}
	//客户端代码
	public static void main(String[] args) {
		Fruit apple = SimpleFruitFactory.getFruit("Apple");
		apple.get();
	}
}

在客户端代码中,直接从工厂中按需取到产品。在增加其他水果时,只需要增加一种水果类、修改工厂,而客户端代码不需要改变。

简单工厂模式的缺点是:所有产品的逻辑都写在一个工厂类中,会导致工厂类臃肿,不利于维护。

工厂模式

一个工厂接口,派生出多个工厂。

产品逻辑分到不同的工厂来写,容易维护,但缺点是会有多个工厂类,产品大量增多时,工厂类也爆炸式增长。

抽象工厂模式

抽象工厂适用于更复杂的情况,用来创建一组相关或相互依赖的对象。

比如在不同水果的基础上,配额不同口味的果酱(Jam.java),制作不同的水果沙拉。

AbstractSaladFactory.java是一个用于生产水果和果酱的接口:

public interface AbstractSaladFactory {
	//获取水果
	public Fruit getFruit();
	//获取果酱
	public Jam getJam();
}

SaladFactory1和SaladFactory2派生自AbstractSaladFactory,是真正生产沙拉的接口。

当需要创建的产品较复杂,比如沙拉同时需要不同种类的水果和果酱,就没有办法再去像工厂模式那样,去定义具体的工厂类,因为没有办法知道到底需要那种水果或是果酱,此时就采用抽象工厂模式。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值