创建型——单例模式
1、单例模式
1.1概述
所谓单例模式就是采取一定的方法保证在整个软件系统中对某个类只存在一个对象实例,并且该类只提供一个获取该对象的静态方法。
1.2 单例设计模式有八种实现方式
1)饿汉式(静态常量)
2)饿汉式(静态代码块)
3)懒汉式(线程不安全)
4)懒汉式(线程安全,同步方法)
5)懒汉式(线程安全,同步代码块)
6)双重检查
-
静态内部类
-
枚举
1.3 饿汉式(静态常量)
**
* @Description: 单例模式的实现方式一:饿汉式(静态常量)
* @author: snow
* @Date: 2020-03-03
**/
public class Singleton1 {
//1.私有化构造器
private Singleton1(){}
//2.创建内部对象实例
private static final Singleton1 instance = new Singleton1();
//3.对外暴露对象实例
public static Singleton1 getInstance(){
return instance;
}
}
优缺点
优点:这种写法比较简单,在类装载的时候就完成了实例化,避免了线程同步问题。
缺点:在类装载的时候就完成了实例化,没有达到Lazy Loading的效果。如果从始至终未使用这个对象,会造成内存浪费。
这种方式基于classloader机制避免了线程同步的问题,不过实例在类装载时就实例化,在单例模式中大多都是调用getInstance方法,但是导致类装载的原因很多,因此不能确有其他的方式导致类装载,这时候初始化instance就没有达到lazy loading的效果。
**结论:**这种方式可用,但是可能会造成内存非浪费。
1.4 饿汉式(静态代码块)
/**
* @Description:饿汉式(静态代码块)
* @author: snow
* @Date: 2020-03-03
**/
public class Singleton2 {
//1.构造器私有化
private Singleton2(){}
//2.创建实例
private static Singleton2 instance;
static {
instance = new Singleton2();
}
//3.对外接口
public static Singleton2 getInstance(){
return instance;
}
}
优缺点
这种方和上面一种方式类似,也是在类装载的时候创建实例,可能会造成内存 的浪费。
1.5 懒汉式(线程不安全)
/**
* @Description:
* @author: snow
* @Date: 2020-03-03
**/
public class Singleton3 {
private Singleton3 (){}
private static Singleton3 instance;
public static Singleton3 getInstance(){
if(instance == null){
instance = new Singleton3();
}
return instance;
}
}
总结: 虽然实现了Lazy Loading,但是因为if判断的原因,在多线程下并不安全,实际开发中一般不能使用。
1.6懒汉式(线程安全,同步方法)
/**
* @Description:
* @author: snow
* @Date: 2020-03-03
**/
public class Singleton3 {
private Singleton3 (){}
private static Singleton3 instance;
public static synchronized Singleton3 getInstance(){
if(instance == null){
instance = new Singleton3();
}
return instance;
}
}
**总结:**解决了线程安全问题,但是效率低,在实际开发中,并不推荐使用。
1.7 双重检查
/**
* @Description:单例模式,双重检查、
* @author: snow
* @Date: 2020-03-03
**/
public class Singleton4 {
private Singleton4(){}
//volatile的总用是使一个变量被修改后立即保存,相当于一个轻量级放入synchronized
private static volatile Singleton4 instance;
public static Singleton4 getInstance(){
if(instance == null){
synchronized (Singleton4.class){
if(instance == null){
instance = new Singleton4();
}
}
}
return instance;
}
}
**总结:**线程安全,符合lazy loading 也避免了反复进行方法同步,效率较高,是开发中推荐使用的单例设计模式
1.8 静态内部类
/**
* @Description:静态内部类方式,
* 类在加载的时候,内部类不会被加载,符合懒加载
* @author: snow
* @Date: 2020-03-03
**/
public class Singleton {
private Singleton (){}
private static class SingleInstance{
private static Singleton instance = new Singleton();
}
public static Singleton getInstance(){
return SingleInstance.instance;
}
}
评价
1)类在加载时其静态内部类不会立即随之加载,当调用getInstance方法时才会被加载。符合懒加载
2)类的静态的属性在类加载时被初始化,所以JVM帮我们保证了线程安全。在类加载时别的线程是无法进入的。
3)推荐使用
1.9 枚举
public enum Singleton {
INSTANCE;
public void sayHello(){
System.out.println("hello");
}
}
public static void main(String[] args) {
Singleton.INSTANCE.sayHello();
}
不仅能够避免多线程同步问题,也能防止反序列化重新创建对象。推荐使用。
2、简单工厂模式
2.1 基本介绍
1)简单工厂模式是工厂模式家族中,最简单最实用的成员之一。
2)其思想就是定义一个工厂类来控制对象群的实例化,当我们面对需要大量实例一些相同或者不同子类的对象群体时。这样做的好处是使对象创建和功能维护(需要新种类的对象或不在需要某一种类的对象)集中控制在第三方,便于管理,而不用去修改使用方的代码或者提供方的代码,符合开闭原则。
2.2 以一个订单的例子,
披萨有不同的种类,对应不同的订单,对应产生不同的对象,是使用工厂模式很好的例子
/**
* @Description:Pizza的基类,
* @author: snow
* @Date: 2020-03-04
**/
public abstract class Pizza {
private String type;
public abstract void prepare();
public void bake(){
System.out.println("烤" + type + "披萨");
}
public void cut(){
System.out.println("切" + type + "披萨");
}
public void box(){
System.out.println("打包" + type + "披萨");
}
public Pizza(String type){
this.type = type;
}
}
/**
* @Description:两种具体得到Pizza
* @author: snow
* @Date: 2020-03-04
**/
public class CheesePizza extends Pizza {
@Override
public void prepare() {
System.out.println("准备奶酪制作奶酪披萨!!");
}
public CheesePizza(String type){
super(type);
}
}
/**
* @Description:
* @author: snow
* @Date: 2020-03-04
**/
public class ChickenPizza extends Pizza {
@Override
public void prepare() {
System.out.println("准备鸡肉,制作鸡肉披萨");
}
public ChickenPizza(String type){
super(type);
}
}
/**
* @Description:负责生产对象的工厂
* @author: snow
* @Date: 2020-03-04
**/
public class SimplePizzaFactory {
public static Pizza createPizza(String type){
Pizza pizza = null;
if(type.equals("cheese")){
pizza = new CheesePizza("cheese");
pizza.prepare();
pizza.bake();
pizza.cut();
pizza.box();
}else if(type.equals("chicken")){
pizza = new ChickenPizza("chicken");
pizza.prepare();
pizza.cut();
pizza.box();
}else{
System.out.println("暂时还没有这个种类的披萨!");
}
return pizza;
}
}
/**
* @Description:订单类
* @author: snow
* @Date: 2020-03-04
**/
public class Order {
private Pizza pizza;
public void doOrder(){
do{
pizza = SimplePizzaFactory.createPizza(getPizzaType());
if(pizza != null){
System.out.println("出售成功!");
}
}while(pizza != null);
}
public String getPizzaType(){
BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
System.out.println("请输入披萨的种类:");
try {
return reader.readLine();
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
}
public class Test {
public static void main(String[] args) {
Order order = new Order();
order.doOrder();
}
}