什么是单利设计模式?
保证一个类只有一个实例,并且提供一个访问该全局访问点。一个jvm中只能存在一个实例,保证对象唯一性。
单例模式应用场景
servlet、struts2、springmvc、连接池、线程池、spring
单例优缺点:
优点:节约内存、重复利用、方便管理
缺点:线程安全问题
单例创建方式(7种)
饿汉式:类初始化时,会立即加载该对象,线程天生安全,调用效率高。
/**
* @program: JAVATest
* @author: 王新春
* @create: 2018-10-30 21:50
* @description: 单例模式---饿汉式
**/
public class Singleton1 {
//2.创建私有化唯一的对象,存在永久区,垃圾回收机制是不会回收
private static final Singleton1 SINGLETON_1 = new Singleton1();
//类初始化的时候,就会创建对象,天生线程安全,如果不使用对象时,会浪费内存
//1.构造函数私有化
private Singleton1() {
}
public static void main(String[] args) {
Singleton1 singleton1 = Singleton1.getInstance();
Singleton1 singleton2 = Singleton1.getInstance();
System.out.println(singleton1 == singleton2);
}
/*
为什么不会存在线程安全问题?
对象唯一不会再被创建
*/
//3.提供外部调用接口
public static Singleton1 getInstance(){
return SINGLETON_1;
}
}
懒汉式:类初始化时,不会初始化该对象,真正需要使用时才会创建该对象,具备懒加载功能。
/**
* @program: JAVATest
* @author: 王新春
* @create: 2018-10-30 21:59
* @description: 单例模式---懒汉式
**/
public class Singleton2 {
//2.创建私有化唯一的对象
private static Singleton2 singleton2;
//类初始化时,不会创建该对象,真正需要时才会被加载(创建),天生线程不安全,,需要解决线程安全问题,所以效率低
//1.构造函数私有化
private Singleton2() {
}
public static void main(String[] args) {
Singleton2 singleton2 = Singleton2.getInstance();
Singleton2 singleton1 = Singleton2.getInstance();
System.out.println(singleton1 == singleton2);
}
//3.提供外部调用接口
/*
线程安全问题
多个线程时,存在创建多个对象的情况
需要解决线程安全问题
*/
public static synchronized Singleton2 getInstance() {
if (singleton2 == null) {
singleton2 = new Singleton2();
}
return singleton2;
}
}
静态内部方式:结合了懒汉式和饿汉式的各自优点,真正需要对象的时候才会加载,加载类是线程安全的。
枚举单例:使用枚举实现单例模式,优点:实现简单、调用效率高,枚举本身就是单例由jvm从根本上提供保障,避免通过反射和反序列化的漏洞,缺点:没有延迟加载功能。
/**
* @program: JAVATest
* @author: 王新春
* @create: 2018-10-30 22:09
* @description: 单例模式---枚举方式
**/
public class Singleton3 {
private Singleton3() {
}
public static Singleton3 getInstance(){
return Singleton3Enum.INSTANCE.getInstance();
}
static enum Singleton3Enum{
INSTANCE;
private Singleton3 singleton3;
private Singleton3Enum() {
this.singleton3 = new Singleton3();
}
public Singleton3 getInstance(){
return this.singleton3;
}
}
public static void main(String[] args) {
Singleton3 singleton3 = Singleton3.getInstance();
Singleton3 singleton2 = Singleton3.getInstance();
System.out.println(singleton3 == singleton2);
}
}
双重检测锁方式(因为jvm本质重排序的原因,可能会初始化多次,不推荐使用)
/**
* @program: JAVATest
* @author: 王新春
* @create: 2018-10-30 22:36
* @description: 单例模式---双重检验锁
**/
public class Singleton4 {
//volatile 本身禁止重排序
private static volatile Singleton4 singleton4;
//1.构造函数私有化
private Singleton4() {
}
public static void main(String[] args) {
Singleton4 singleton2 = Singleton4.getInstance();
Singleton4 singleton1 = Singleton4.getInstance();
System.out.println(singleton1 == singleton2);
}
//3.提供外部调用接口
/*
线程安全问题
多个线程时,存在创建多个对象的情况
需要解决线程安全问题,使用双重检验锁,可以增加安全性,但是会降低效率
*/
public static Singleton4 getInstance() {
if (singleton4 == null) {
synchronized (Singleton4.class){
if (singleton4 == null) {
singleton4 = new Singleton4();//存在重排序问题
}
}
}
return singleton4;
}
}
什么时工厂模式?
实现了创建者和调用者分离,工厂模式分为简单工厂、工厂方法、抽象工厂模式。
简单工厂设计模式(不属于23种设计模式)
简单工厂模式是属于创建型模式,又叫做静态工厂方法(Static Factory Method)模式,但不属于23种GOF设计模式之一。简单工厂模式是由一个工厂对象决定创建出哪一种产品类的实例。简单工厂模式是工厂模式家族中最简单实用的模式,可以理解为是不同工厂模式的一个特殊实现。
优点:简单工厂模式能够根据外界给定的信息,决定究竟应该创建哪个具体类的对象。明确区分了各自的职责和权力,有利于整个软件体系结构的优化
缺点:很明显工厂类集中了所有实例的创建逻辑,容易违反GRASPR的高内聚的责任分配原则
举一个去4s点买汽车的例子
汽车接口
/**
* @program: JAVATest
* @author: 王新春
* @create: 2018-10-31 22:30
* @description: 总汽车类型
**/
public interface Car {
void run();
}
汽车子类
/**
* @program: JAVATest
* @author: 王新春
* @create: 2018-10-31 22:31
* @description: 比亚迪汽车
**/
public class Byd implements Car {
@Override
public void run() {
System.out.println("比亚迪汽车在跑。。。。");
}
}
/**
* @program: JAVATest
* @author: 王新春
* @create: 2018-10-31 22:33
* @description: 奔驰G500
**/
public class BCG500 implements Car {
@Override
public void run() {
System.out.println("奔驰G500在跑。。。");
}
}
工厂类
/**
* @program: JAVATest
* @author: 王新春
* @create: 2018-10-31 22:34
* @description: 工厂模式-----简单工厂
**/
public class CarFactory {
public static Car createCar(String name){
if(name == null || name == ""){
return null;
}
/*
当类型过多时,不利于维护,也不利于扩展
*/
switch (name){
case "比亚迪":
return new Byd();
case "奔驰G500":
return new BCG500();
default:
return null;
}
}
}
测试类
/**
* @program: JAVATest
* @author: 王新春
* @create: 2018-10-31 22:45
* @description: 测试类
**/
public class TestMain {
public static void main(String[] args) {
Car bcg500 = CarFactory.createCar("奔驰G500");
bcg500.run();
}
}
输出为:奔驰G500在跑。。。