一、单例模式
确保一个类只有一个实例,而且自行实例化并向这个系统提供这个实例
- 构造方法不能公开,不能被外界进行实例化,只能是private
- 只有一个实例,并且这个实例属于当前类,则这个类是当前类的类成员变量,即静态变量
- 还需要向整个系统提供这个实例,因此还需要一个静态的方法,向外界提供当前类的实例
分为饿汉式和懒汉式
饿汉式
:唯一实例只在类记载的时候立马得到实例
class Singleton{
//构建属性的时候同时实现类的实例
private static Singleton singleton = new Singleton();
private Singleton(){} //将构造方法私有化
public static Singleton getInstance(){
return singleton;
}
}
懒汉式:不在类加载的时候进行实例化,而是在使用的时候进行实例化
class Singleton{
private static Singleton singleton = null;
private Singleton(){} //将构造方法私有化
//在调用getInstace方法的时候才会进行实例化
//加锁:防止被多次实例化
public synchronized static Singleton getInstance(){
if(singleton == null)
single=new Instance();
return singleton;
}
}
懒汉式还有换一种经典的实现的方式:双重检查锁
在同步处理的时候是整个方法,而实例化只发生在第一次,因此可以减小同步的范围
每次都得在方法加锁太麻烦,可以在第一判断为空的时候进行加锁,以便进行实例化
双重我的理解是volatile和synchronized称为双重锁
calss Singleton{
// 必须使用volatile修饰,防止指令进行重排序
private static volatile Singleton singleton = null;
private Singleton(){}
private static Singleton getInstance(){
if(singleton == null){
synchronized(Singleton.clas) //反射,将.class文件进行加锁
if(singleton == null){
singleton = new Singleton();
}
}
return singleton;
}
}
singleton = new Singleton();应该分为三步
- 分配内存
- 实例化对象
- 指向刚分配的地址
// 防止进行内存的优化的进行重排序,导致多线程出现错误
采用双重锁之后,只会在第一次获取实例的时候才需要执行同步锁,以后得直接去获得,提高获取实例的速度
一定的情况下单例模式也会出现多个实例
比如具有多个虚拟机,各个虚拟机都有一个实例。另一个就是同一个JVM,使用多个类加载器生成多个实例。因为他只用Synchronized锁住了.class文件
单例模式的最佳模式是无状态的,所以最好的就是用于实现类的编写
补充使用静态内部类创建类的实例或枚举
class Singleton{
private Singleton(){}
//一定是线程安全的
//使用静态内部类的方式实现懒加载 (只有用的时候才加载)
private static class LazyHolder{
private static final Singleton singleton = new Singleton();
}
public static final Singleton getInstance(){
return LazyHolder.singleton;
}
}
//静态内部类 要创建实例,使用final来修饰,防止多线程进行修改 // 此外获取类实例的方法,也用final来修饰
二、责任链模式
是一种处理请求的模式,他让多个处理器都有机会处理该请求,知道其中某个处理成功为止。将多个处理器串成链,然后让请求在链上传递(类似请假,层层审批) 一条链去处理相同的请求,并在链上决定谁来处理这个请求并返回相应的结果
- 设置一个抽象类,其中包括处理消息和给下一个节点消息的方法
- 作为链上的一个节点,只需要去实现这个方法
//定义一个抽象类:
abstract calss Handler{
//两个方法:一个分发的,一个处理消息的:
protetcted Handler nextHandler;
public void setHandler(Handler nextHandler){
this.nextHandler = nextHandler;
}
public abstract void process(Integer info);
}
//处理问题的节点
class leader extends Handler{
public void process(Integer info){
if(info>0&&info<10){
sout("我只能处理到10级别的消息");
}else
nextHandler.process(info);
}
}
//noss级别的处理更高的请求
class Boss extends Handler{
public void process(Integer info){
if(info>10){
sout("我处理到10级别以上的消息");
}
}
}
优点:将请求和处理进行分开,请求者不知道谁去处理,处理着也不知道请求的全貌
缺点:每一个请求需要从链头走向链尾,当链比较长的时候性能会大幅度下降.类似于递归的方式,不易于去调试
三、模板方法模式
类似于做菜,步骤都整理好了,但是只有比如两步,具体的实现没有
//定义一个抽象类
abstract class Cooking{
protected abstract void step1();
protected abstract void step2();
public void cook(){
sout("做饭开始");
step1();
step2();
sout("做饭结束");
} //所以抽象类可以有具体的方法,而接口不可以
}
calss CookingFood extends Cooking{
protected void step1(){
sout("放鸡蛋和西红柿");
}
protected void step2(){
sout("少放盐和多放味精");
}
}
psvm{
Cooking cook = new CokingFood();
cook.cook();
}
四、工厂模式(BeanDefinition)
五、组合模式(ApplicationContext和BeanFactory)
六、策略模式
干掉if else