单例设计模式
某个类只存在一个对象实例,对外也只提供一个取得该对象实例的方法,而不是用new。
1.饿汉式
- 私有化构造方法,使得外部不能new
- 静态化成员对象实例
- 静态化调用实例的方法
class Singleton {
private Singleton() {}
private final static Singleton instance = new Singleton();
public static Singleton getInstance() {
return instance;
}
}
public class en{
public static void main(String[] args) throws IOException {
Singleton in1=Singleton.getInstance();
Singleton in2=Singleton.getInstance();
System.out.println(in1==in2);//true
}
}
类装载的时候就完成了实例化,可以避免线程同步问题,但是可能会造成资源浪费。因为如果有其他方式触发了类装载,但是一直没有用类里面的实例,就造成了浪费。
2.懒汉式
当真正调用到getInstance方法时才创建一个实例,不会造成浪费,如以下代码,但是可能会产生线程安全问题。因为可能会有多个线程进入if(instance==null)处,创建出多个实例。
怎么解决? 加锁!
class Singleton {
private Singleton() {}
private static Singleton instance;
public static Singleton getInstance() {
if(instance==null){
instance=new Singleton();
return instance;
}
return instance;
}
}
考虑在getInstance方法上加锁,确实可以保证线程同步,但是效率太低了。因为线程同步与否主要产生在实例未创建但是有大量线程进入的情况,当某个线程已经创建了这个实例,其他线程是不需要同步的,直接返回实例就可以了。
class Singleton {
private Singleton() {}
private static Singleton instance;
public static synchronized Singleton getInstance() {
if(instance==null){
synchronized (Singleton.class){
if(instance==null)
instance=new Singleton();
}
}
return instance;
}
}
为了解决上述效率低的问题,用volatile关键字修饰instance,使得不同线程每次读到instance变量都能获取到最新值,进行双重检查。
class Singleton {
private Singleton() {}
private static volatile Singleton instance;
public static synchronized Singleton getInstance() {
if(instance==null){
synchronized (Singleton.class){
if(instance==null)
instance=new Singleton();
}
}
return instance;
}
}
使用静态内部类,因为外部类加载的时候内部类不会马上被加载,而是在需要时才加载,实现了慢加载。又因为类加载的时候是线程安全的且只加载一次,所以提供了线程安全。
class Singleton {
private Singleton() {}
private static class SingletonInstance{
private static final Singleton INSTANCE=new Singleton();
}
public static synchronized Singleton getInstance() {
return SingletonInstance.INSTANCE;
}
}
枚举实现也可以
因为Java虚拟机会保证枚举对象的唯一性,因此每一个枚举类型和定义的枚举变量在JVM中都是唯一的。
enum Singleton{
INSTANCE;
}
当碰见需要频繁创建和销毁,但是又经常使用的对象,推荐使用单例模式比如工具类,提高速度。
工厂设计模式
工厂模式的意义:将实例化对象的代码提取出来,放到一个类中统一管理和维护,达到和主项目的依赖关系的解耦。从而提高项目的扩展和维护性。
1.简单工厂
简单来讲就是所有对象都由一个工厂产生,如果要增加物品,工厂对象的代码必须要修改,违反了开闭原则。
2.工厂方法
工厂方法类是将原来一个工厂变成多个工厂,每个工厂处理一种类型的物品。这些工厂可以继承于总工厂也可以不继承直接实现出来。调用的时候比如要生成meizu手机,直接调用
Phone = new MeizuFactory(参数看情况);
这种用法在Spring中非常普遍。
3.抽象工厂方法模式
抽象工厂模式是设置一个抽象工厂接口,实现类工厂实现工厂接口。每个实现类管理着各自的类。
在调用的时候应该对外提供抽象工厂的接口作为参数,实际接受的是抽象工厂的实现类工厂。
public class OrderPizza{
private AbsFactory absFactory;
public Pizza getPizza(AbsFactory absFactory,String orderType){//传进来的是工厂实现类
this.absFactory=absFactory;
return this.absFactory.createPizza(orderType);
}
}
外部调用
Pizza LDCheesePizza = new OrderPizza(new LDFactory(),Cheese).;
Spring中的设计模式
单例模式
- bean默认使用的就是单例模式singleton,使得IOC容器中至多只能出现一个bean实例对象。底层是一个ConcurrentHashMap实现,去校验IOC容器中是否存在这个bean实例对象。
工厂模式
- Spring 使用工厂模式可以通过 BeanFactory 或 ApplicationContext 创建 bean对象。
- 两者对比:BeanFactory:延迟注入(使用到某个 bean 的时候才会注入),相比于ApplicationContext来说会占用更少的内存,程序启动速度更快。ApplicationContext:容器启动的时候,不管你用没用到,一次性创建所有 bean 。BeanFactory 仅提供了最基本的依赖注入支持,ApplicationContext 扩展了 BeanFactory,除了有BeanFactory的功能还有额外更多功能,所以一般开发人员使用ApplicationContext会更多。
适配器模式
- 在Spring MVC中,核心分配DispatcherServlet接受web请求后从HandleMapping中获得需要的Handler(controller),如果说没有实现HandlerAdapter,因为不同的请求他的controller不一样,那么DispatcherServlet就要自己找合适的controller,不好维护,违反了开闭原则,所以实现了HandlerAdapter暴露需要的接口。