单例模式主要是为了避免因为创建了多个实例造成资源的浪费,且多个实例由于多次调用容易导致结果的出错。而使用单例模式能够保证整个应用只有一个实例
在整个应用中(一般只用一个IOC
容器),只创建Bean的一个实例,多次注入同一具体类时都是注入同一个实例。
IOC
容器来实现过程简述如下:
当需要注入Bean时,IOC
容器首先解析配置找到具体类,然后判断其作用域(@Scope注解);
默认的单例@Scope(ConfigurableBeanFactory.SCOPE_SINGLETON)
,则查找容器中之前有没有为其创建了Bean实例;如果有则直接注入该Bean实例,如果没有生成一个放到容器中保存
(ConcurrentHashMap -- map.put(bean_id, bean)
),再注入。
注:其中解析配置查找具体类、生成Bean实例和注入过程都是通过Java反射机制实现的。
ConfigFile
中有很多数据时,如果将其全部设成静态的,那将是对内存的极大损耗。①懒汉式
/**
@author maxu
@date 2018/11/3
优点:从它的实现中我们可以看到,这种方式的实现比较简单,在类加载的时候就完成了实例化,避免了线程的同步
* 问题。
缺点:由于在类加载的时候就实例化了,所以没有达到Lazy Loading(懒加载)的效果,也就是说可能我没有用到
* 这个实例,但是它也会加载,会造成内存的浪费(但是这个浪费可以忽略,所以这种方式也是推荐使用的)。
*/
public class Singleton {
private static Singleton instance = new Singleton();
private Singleton() {}
public static Singleton getInstance() {
return instance;
}
}
②饿汉式
public class Singleton {
private static Singleton instance = null;
private Singleton() {}
public static Singleton getInstance() {
if (null == instance) {
instance = new Singleton();
}
return instance;
}
}
③双重校验锁
public class Singleton {
private static Singleton instance = null;
private Singleton() {
}
public static synchronized Singleton getInstance() {
if (null == instance) {
synchronized (Singleton.class) {
if (null == instance) {
instance = new Singleton();
}
}
}
return instance;
}
}
④静态内部类
/**
* 这种方式跟饿汉式方式采用的机制类似,但又有不同。两者都是采用了类装载的机制来保证初始化实例时只有一个线程。不同
* 的地方在饿汉式方式是只要Singleton类被装载就会实例化,没有Lazy-Loading的作用,而静态内部类方式在Singleton类被装载时
* 并不会立即实例化,而是在需要实例化时,调用getInstance方法,才会装载SingletonHolder类,从而完成Singleton的实例化。
* 类的静态属性只会在第一次加载类的时候初始化,所以在这里,JVM帮助我们保证了线程的安全性,在类进行初始化时,别的线程是无法进入的
* 优点:避免了线程不安全,延迟加载,效率高。
*/
public class Singleton {
private Singleton() {
}
private static class Sinletonleader {
private static Singleton singleton = new Singleton();
}
public Singleton getInstance() {
return Sinletonleader.singleton;
}
}
⑤枚举
/**
* SingletonEnum.instance.method();
* 借助JDK1.5中添加的枚举来实现单例模式。不仅能避免多线程同步问题,
* 而且还能防止反序列化重新创建新的对象。可能是因为枚举在JDK1.5中才添加,所以在实际项目开发中
* 很少见人这么写过,这种方式也是最好的一种方式,如果在开发中JDK满足要求的情况下建议使用这种方式。
*/
public enum Singleton {
instance;
private Singleton() {
}
public void method() {
}
}
是由一个对象根据收到的消息决定要创建哪一个类的对象实例。
使用场景:工厂类负责创建的对象比较少,客户只需要传入工厂参数,对于如何创建对象不关心,违反了高内聚低耦合的原则。
最大的优点:工厂类包含了必要的逻辑根据用户的需要逻辑动态实例化相关的类。
缺点:只能生产同一级结构的产品,在添加新产品的时候需要修改代码
定义一个创建对象的工厂接口,让子类去决定实例化哪一个类,将实例化的工作延迟到子类当中。
场景:数据库访问的时候用户不知到最后系统采用那一个数据库以及数据库有什么变化。
特点:用来产生统一等级下结构的产品,支持增加任意的产品。
首先定义一个被观察者的接口Observerable
/**
* @author maxu
* @date 2018/11/3
* 抽象者被观察者方法
*/
public interface Observerable {
void registerObserver(Observer observer);
void removeObserver(Observer observer);
void notifyObserver();
}
/**
* @author maxu
* @date 2018/11/3
* 定义了一个update()方法,当被观察者调用notifyObservers()方法时,观察者的update()方法会被回调。
* 观察者
*/
public interface Observer {
void update(String message);
}
/**
* @author maxu
* @date 2018/11/3
*/
public class WechatServer implements Observerable {
/**
* 注意到这个List集合的泛型是Observer
*/
// 这里保存着所有注册的观察者
private List<Observer> list;
private String message;
public WechatServer() {
list = new ArrayList<>();
}
// 注册观察者
@Override
public void registerObserver(Observer observer) {
list.add(observer);
}
// 移除观察者
@Override
public void removeObserver(Observer observer) {
if (!list.isEmpty()) {
list.remove(observer);
}
}
// 通知所有的观察者的具体实现
@Override
public void notifyObserver() {
for (Observer observer : list) {
observer.update(message);
}
}
/**
* 发布消息,并通知给所有观察者
* @param message
*/
public void setInfomation(String message) {
this.message = message;
notifyObserver();
}
}
/**
* @author maxu
* @date 2018/11/3
* 观察者
*/
public class User implements Observer {
private String name;
private String message;
public User(String name) {
this.name = name;
}
@Override
public void update(String message) {
this.message = message;
read();
}
public void read(){
System.out.println(name + "收到的消息" + message);
}
}
/**
* @author maxu
* @date 2018/11/3
*/
public class Test {
public static void main(String[] args) {
WechatServer server = new WechatServer();
Observer user1 = new User("张山");
Observer user2 = new User("小马");
Observer user3 = new User("小白");
server.registerObserver(user1);
server.registerObserver(user2);
server.registerObserver(user3);
server.setInfomation("java是最好的语言");
System.out.println("----------------------------------");
server.removeObserver(user1);
server.setInfomation("php是最好的语言");
}
}
原有的类不能满足现有的需求,对原有类的进行增强
装饰器模式特点在于增强,他的特点是被装饰类和所有的装饰类必须实现同一个接口,而且必须持有被装饰的对象,可以无限装饰。
Component 是一个接口,或者是一个抽象类,这就是定义我们最核心的对象,也就是最原始的对象。
ConreteComponent这是最核心、最原始、最基本的接口或者抽象方法,它里面可不一定有抽象方法呀,
在它的属性里必然有一个private属性指向Component。
ConcreteDecoratorA和ConcreteDecoratorB 是两个具体的装饰类,你要把你最核心的、最原始的、最基本的东西装饰成什么。
装饰模式是对继承的的补充,装饰模式可以解决继承膨胀的问题,继承是静态的给类增加新的功能,然而装饰模式是对类进行动态的增加新的功能。
装饰模式还有一个有点就是很好的扩展,装饰模式通过封装一个类而不是通过继承来完成。
简单点说,有三个继承关系 Father Son GrandSon 三个类,我要在Son类上添加新的功能?那么对GrandSon的影响呢,如果是多个GrandSon的时候,你评估就要做的很心累,所以我们可以新创建一个DectoratorSon来封装Son这个类。这样在增强Son的时候对GrandSon就不会产生影响了。
定义一个模板结构,将具体的内容延迟到子类中去实现。
在不改变模板结构的前提下在子类中重新定义模板中的内容
。
模板方法的模式是基于继承
的。
将一个类的接口转换成用户希望的另一个接口。
适配器模式剋让那些接口不兼容的类可以一起工作。
通常情况下,客户端可以通过目标类的接口访问它所提供的服务。有时,现有的类可以满足客户类的功能需要,但是它所提供的接口不一定是客户类所期望的,这可能是因为现有类中方法名与目标类中定义的方法名不一致等原因所导致的。
在适配器模式中,可以定义一个包装类,包装不兼容接口对象,这个包装类指的就是适配器,它所包装的对象就是适配者,就是被适配的类。
适配器提供用户类所需要的接口,适配器的实现就是把客户类的请求转化为对适配者响应接口的调用。简单来说,当客户类调用适配器方法的时候,在适配器内部将调用适配者类的方法,而这个过程对客户类是透明的,客户类并不直接访问适配者类,因此,适配器可以使由于接口不兼容而不能相互工作的类一起工作。
public class Adapter extends Adaptee implements Target {
public void request() {
specificRequest();
}
}
在这里插入图片描述
public class Adapter extends Target{
private Adaptee adaptee;
public Adapter(Adaptee adaptee){
this.adaptee=adaptee;
}
public void request(){
adaptee.specificRequest();
}
}
public abstract class Handler{
protected Handler successor;
public void setSuccessor(Handler successor){
this.successor=successor;
}
public abstract void handleRequest(String request);
}
public class ConcreteHandler extends Handler {
public void handleRequest(String request) {
if(请求request满足条件) {
...... //处理请求;
} else {
this.successor.handleRequest(request); //转发请求
}
}
}
某OA系统需要提供一个假条审批的模块,如果员工请假天数小于3天,主任可以审批该假条;如果员工请假天数大于等于3天,小于10天,经理可以审批;如果员工请假天数大于等于10天,小于30天,总经理可以审批;如果超过30天,总经理也不能审批,提示相应的拒绝信息。
一个纯的职责链模式要求一个具体处理者对象只能在两个行为中选择一个:一个是承担责任,另一个是把责任推给下家。不允许出现某一个具体处理者对象在承担了一部分责任后又将责任向下传的情况。
在一个纯的职责链模式里面,一个请求必须被某一个处理者对象所接收;在一个不纯的职责链模式里面,一个请求可以最终不被任何接收端对象所接收。
在某些情况下,一个客户不想或者不能直接引用一个对象,此时可以通过一个称之为“代理”的第三者来实现间接引用。代理对象可以在客户端和目标对象之间起到中介的作用,并且可以通过代理对象去掉客户不能看到的内容和服务或者添加客户需要的额外服务。
通过引入一个新的对象来实现对真实对象的操作或者将新的对象作为真实对象的一个替身,这种实现机制即为代理模式,通过引入代理对象来间接访问一个对象,这就是代理模式的模式动机。
public class Proxy implements Subject {
// 创建真实对象
private RealSubject realSubject = new RealSubject();
public void preRequest(){...}
public void request(){
preRequest();
realSubject.request();
postRequest();
}
public void afterRequest(){...}
}
由于在客户端和真实主题之间增加了代理对象,因此有些类型的代理模式可能会造成请求的处理速度变慢。
实现代理模式需要额外的工作,有些代理模式的实现非常复杂。