一、设计模式概述
总体来说设计模式分为三大类:
创建型模式 创建型模式 创建型模式 ,共五种:工厂方法模式、抽象单例建造者原型 ,共五种:工厂方法模式、抽象单例建造者原型 ,共五种:工厂方法模式、抽象单例建造者原型 ,共五种:工厂方法模式、抽象单例建造者原型 ,共五种:工厂方法模式、抽象单例建造者原型 ,共五种:工厂方法模式、抽象单例建造者原型 ,共五种:工厂方法模式、抽象单例建造者原型 ,共五种:工厂方法模式、抽象单例建造者原型 模式。
结构型模式, 结构型模式, 结构型模式, 结构型模式, 结构型模式, 结构型模式, 共七种:适配器模式、 装饰代理外观桥接共七种:适配器模式、 装饰代理外观桥接共七种:适配器模式、 装饰代理外观桥接共七种:适配器模式、 装饰代理外观桥接共七种:适配器模式、 装饰代理外观桥接共七种:适配器模式、 装饰代理外观桥接共七种:适配器模式、 装饰代理外观桥接共七种:适配器模式、 装饰代理外观桥接共七种:适配器模式、 装饰代理外观桥接组合模式、享元。
行为型模式, 行为型模式, 行为型模式, 共十一种:策略模式、板方法观察者迭代子责任 共十一种:策略模式、板方法观察者迭代子责任 共十一种:策略模式、板方法观察者迭代子责任 共十一种:策略模式、板方法观察者迭代子责任 共十一种:策略模式、板方法观察者迭代子责任 共十一种:策略模式、板方法观察者迭代子责任 共十一种:策略模式、板方法观察者迭代子责任 共十一种:策略模式、板方法观察者迭代子责任 共十一种:策略模式、板方法观察者迭代子责任 链模式、命令备忘录状态访问者中介解释器。
具体如下:
其中创建型有:
一、 Singleton Singleton SingletonSingletonSingleton,单例模式:保证一个类只有实,并提供访问它的全局 ,单例模式:保证一个类只有实并提供访问它的全局 ,单例模式:保证一个类只有实并提供访问它的全局 ,单例模式:保证一个类只有实并提供访问它的全局 ,单例模式:保证一个类只有实并提供访问它的全局 ,单例模式:保证一个类只有实并提供访问它的全局 ,单例模式:保证一个类只有实并提供访问它的全局 ,单例模式:保证一个类只有实并提供访问它的全局 ,单例模式:保证一个类只有实并提供访问它的全局 ,单例模式:保证一个类只有实并提供访问它的全局 ,单例模式:保证一个类只有实并提供访问它的全局 ,单例模式:保证一个类只有实并提供访问它的全局 ,单例模式:保证一个类只有实并提供访问它的全局 ,单例模式:保证一个类只有实并提供访问它的全局 ,单例模式:保证一个类只有实并提供访问它的全局 ,单例模式:保证一个类只有实并提供访问它的全局 ,单例模式:保证一个类只有实并提供访问它的全局 ,单例模式:保证一个类只有实并提供访问它的全局 访问 点
二、 Abstract Factory Abstract FactoryAbstract FactoryAbstract FactoryAbstract Factory Abstract FactoryAbstract FactoryAbstract Factory Abstract FactoryAbstract Factory , 抽象工厂:提供一个创建系列相关或互依赖对的接口, 抽象工厂:提供一个创建系列相关或互依赖对的接口, 抽象工厂:提供一个创建系列相关或互依赖对的接口, 抽象工厂:提供一个创建系列相关或互依赖对的接口, 抽象工厂:提供一个创建系列相关或互依赖对的接口, 抽象工厂:提供一个创建系列相关或互依赖对的接口, 抽象工厂:提供一个创建系列相关或互依赖对的接口, 抽象工厂:提供一个创建系列相关或互依赖对的接口, 抽象工厂:提供一个创建系列相关或互依赖对的接口, 抽象工厂:提供一个创建系列相关或互依赖对的接口而无须指定它们的具体类。
三、 Factory MethodFactory Method Factory MethodFactory Method Factory MethodFactory MethodFactory MethodFactory MethodFactory Method,工厂方法:定义一个用于创建对象的接口,让子类决实例化哪 ,工厂方法:定义一个用于创建对象的接口让子类决实例化哪 ,工厂方法:定义一个用于创建对象的接口让子类决实例化哪 ,工厂方法:定义一个用于创建对象的接口让子类决实例化哪 ,工厂方法:定义一个用于创建对象的接口让子类决实例化哪 一个类, Factory MethodFactory Method Factory MethodFactory Method Factory MethodFactory MethodFactory MethodFactory MethodFactory Method使一个类的实例化延迟到了子。
四、 BuilderBuilderBuilder Builder ,建 造模式:将一个复杂对象的构与他表示相分离使得同样,建 造模式:将一个复杂对象的构与他表示相分离使得同样,建 造模式:将一个复杂对象的构与他表示相分离使得同样,建 造模式:将一个复杂对象的构与他表示相分离使得同样,建 造模式:将一个复杂对象的构与他表示相分离使得同样,建 造模式:将一个复杂对象的构与他表示相分离使得同样,建 造模式:将一个复杂对象的构与他表示相分离使得同样,建 造模式:将一个复杂对象的构与他表示相分离使得同样,建 造模式:将一个复杂对象的构与他表示相分离使得同样,建 造模式:将一个复杂对象的构与他表示相分离使得同样过程可以创建不同的表示。
五、 Prototype PrototypePrototypePrototypePrototypePrototype ,原型 模式:用实例指定创建对象的种类并且通过拷贝这些,原型 模式:用实例指定创建对象的种类并且通过拷贝这些,原型 模式:用实例指定创建对象的种类并且通过拷贝这些,原型 模式:用实例指定创建对象的种类并且通过拷贝这些,原型 模式:用实例指定创建对象的种类并且通过拷贝这些来创建新的对象。
行为型有 :
六、 Iterator Iterator IteratorIteratorIteratorIterator,迭代器模式:提供一个方法顺序访问聚合对象的各元素,而又不 ,迭代器模式:提供一个方法顺序访问聚合对象的各元素而又不 ,迭代器模式:提供一个方法顺序访问聚合对象的各元素而又不 ,迭代器模式:提供一个方法顺序访问聚合对象的各元素而又不 ,迭代器模式:提供一个方法顺序访问聚合对象的各元素而又不 需要暴露该对象的内部表示。
七、 Observer Observer ObserverObserverObserver,观察者模式:定义对象间一多的依赖关系,当个状态发生 ,观察者模式:定义对象间一多的依赖关系当个状态发生 ,观察者模式:定义对象间一多的依赖关系当个状态发生 ,观察者模式:定义对象间一多的依赖关系当个状态发生 ,观察者模式:定义对象间一多的依赖关系当个状态发生 ,观察者模式:定义对象间一多的依赖关系当个状态发生 ,观察者模式:定义对象间一多的依赖关系当个状态发生 ,观察者模式:定义对象间一多的依赖关系当个状态发生 ,观察者模式:定义对象间一多的依赖关系当个状态发生 ,观察者模式:定义对象间一多的依赖关系当个状态发生 ,观察者模式:定义对象间一多的依赖关系当个状态发生 ,观察者模式:定义对象间一多的依赖关系当个状态发生 ,观察者模式:定义对象间一多的依赖关系当个状态发生 ,观察者模式:定义对象间一多的依赖关系当个状态发生 ,观察者模式:定义对象间一多的依赖关系当个状态发生 ,观察者模式:定义对象间一多的依赖关系当个状态发生 ,观察者模式:定义对象间一多的依赖关系当个状态发生 ,观察者模式:定义对象间一多的依赖关系当个状态发生 ,观察者模式:定义对象间一多的依赖关系当个状态发生 ,观察者模式:定义对象间一多的依赖关系当个状态发生 ,观察者模式:定义对象间一多的依赖关系当个状态发生 ,观察者模式:定义对象间一多的依赖关系当个状态发生 ,观察者模式:定义对象间一多的依赖关系当个状态发生 ,观察者模式:定义对象间一多的依赖关系当个状态发生 ,观察者模式:定义对象间一多的依赖关系当个状态发生 改变时,所有依赖于它的对象都得到通知自动更新。
八、 Template MethodTemplate Method Template MethodTemplate Method Template MethodTemplate Method Template MethodTemplate MethodTemplate MethodTemplate MethodTemplate MethodTemplate Method,模板方法:定义一个操作中的算骨架,而将些步骤延迟 ,模板方法:定义一个操作中的算骨架而将些步骤延迟 ,模板方法:定义一个操作中的算骨架而将些步骤延迟 ,模板方法:定义一个操作中的算骨架而将些步骤延迟 到子类中, TemplateMethodTemplateMethod TemplateMethodTemplateMethod TemplateMethodTemplateMethod TemplateMethodTemplateMethodTemplateMethodTemplateMethodTemplateMethod使得子类可以不改变一个算法的结构即重定义该某 使得子类可以不改变一个算法的结构即重定义该某 些特定步骤。
九、 Command CommandCommand,命令模式:将一个请求封装为对象,从而使 ,命令模式:将一个请求封装为对象从而使 ,命令模式:将一个请求封装为对象从而使 ,命令模式:将一个请求封装为对象从而使 ,命令模式:将一个请求封装为对象从而使 你可以用不同的请求 对客户进行参数化,请求排队和记录日志以及支持可撤销的操作。
十、 State StateStateState,状态模式:允许对象在其内部改变时他的行为。看起来似乎 ,状态模式:允许对象在其内部改变时他的行为。看起来似乎 ,状态模式:允许对象在其内部改变时他的行为。看起来似乎 ,状态模式:允许对象在其内部改变时他的行为。看起来似乎 改变了他的类。
十一、 Strategy StrategyStrategyStrategyStrategy ,策略模式:定义一系列的算法把他们个封装起来并使可 ,策略模式:定义一系列的算法把他们个封装起来并使可 ,策略模式:定义一系列的算法把他们个封装起来并使可 ,策略模式:定义一系列的算法把他们个封装起来并使可 ,策略模式:定义一系列的算法把他们个封装起来并使可 以互相替换,本模式使得算法可独立于用它们的客户。
十二、 China of Responsibility China of Responsibility China of ResponsibilityChina of ResponsibilityChina of ResponsibilityChina of ResponsibilityChina of Responsibility China of ResponsibilityChina of ResponsibilityChina of Responsibility China of ResponsibilityChina of Responsibility China of Responsibility,职责链模式:使多个对象都有机会处理请求,从而避免 ,职责链模式:使多个对象都有机会处理请求从而避免 ,职责链模式:使多个对象都有机会处理请求从而避免 ,职责链模式:使多个对象都有机会处理请求从而避免 ,职责链模式:使多个对象都有机会处理请求从而避免 请求的送发者和接收之间耦合关系
十三、 MediatorMediator Mediator MediatorMediatorMediator,中介 者模式:用一个,中介 者模式:用一个对象封装一些列的交互。
十四、 VisitorVisitor VisitorVisitor,访问者模式:表示一个作用于某对象结构中的各元素操,它使你 ,访问者模式:表示一个作用于某对象结构中的各元素操它使你 ,访问者模式:表示一个作用于某对象结构中的各元素操它使你 可以在不改变各元素类的前提下定义作用于这个新操。
十五、 Interpreter InterpreterInterpreter InterpreterInterpreterInterpreter ,解释器模式:给定一 个语言义他的文法表示并,解释器模式:给定一 个语言义他的文法表示并,解释器模式:给定一 个语言义他的文法表示并,解释器模式:给定一 个语言义他的文法表示并,解释器模式:给定一 个语言义他的文法表示并,解释器模式:给定一 个语言义他的文法表示并,解释器模式:给定一 个语言义他的文法表示并,解释器模式:给定一 个语言义他的文法表示并个解释器,这使用该表示来语言中的句子。
十六、 MementoMemento Memento MementoMemento,备忘录模式:在不破坏对象的前提下, 捕获一个内部状态, 备忘录模式:在不破坏对象的前提下捕获一个内部状态, 备忘录模式:在不破坏对象的前提下捕获一个内部状态, 备忘录模式:在不破坏对象的前提下捕获一个内部状态, 备忘录模式:在不破坏对象的前提下捕获一个内部状态, 备忘录模式:在不破坏对象的前提下捕获一个内部状态, 备忘录模式:在不破坏对象的前提下捕获一个内部状态, 备忘录模式:在不破坏对象的前提下捕获一个内部状态, 备忘录模式:在不破坏对象的前提下捕获一个内部状态, 备忘录模式:在不破坏对象的前提下捕获一个内部状态, 备忘录模式:在不破坏对象的前提下捕获一个内部状态, 备忘录模式:在不破坏对象的前提下捕获一个内部状态, 备忘录模式:在不破坏对象的前提下捕获一个内部状态, 备忘录模式:在不破坏对象的前提下捕获一个内部状态, 备忘录模式:在不破坏对象的前提下捕获一个内部状态, 备忘录模式:在不破坏对象的前提下捕获一个内部状态, 备忘录模式:在不破坏对象的前提下捕获一个内部状态, 备忘录模式:在不破坏对象的前提下捕获一个内部状态, 备忘录模式:在不破坏对象的前提下捕获一个内部状态, 备忘录模式:在不破坏对象的前提下捕获一个内部状态, 备忘录模式:在不破坏对象的前提下捕获一个内部状态, 备忘录模式:在不破坏对象的前提下捕获一个内部状态, 备忘录模式:在不破坏对象的前提下捕获一个内部状态, 备忘录模式:在不破坏对象的前提下捕获一个内部状态, 备忘录模式:在不破坏对象的前提下捕获一个内部状态, 备忘录模式:在不破坏对象的前提下捕获一个内部状态, 备忘录模式:在不破坏对象的前提下捕获一个内部状态, 备忘录模式:在不破坏对象的前提下捕获一个内部状态, 备忘录模式:在不破坏对象的前提下捕获一个内部状态, 备忘录模式:在不破坏对象的前提下捕获一个内部状态并在该对象之外保存这个状态。
结构型有:
十七、 Composite CompositeComposite Composite,组合模式:将对象成树形结构以表示部分整体的 ,组合模式:将对象成树形结构以表示部分整体的 ,组合模式:将对象成树形结构以表示部分整体的 ,组合模式:将对象成树形结构以表示部分整体的 关系, Composite CompositeComposite Composite使得用户对单个象和组合的具有一致性。
十八、 FacadeFacade Facade Facade,外观模式:为子系统中的一组接口提供致界面, fa?adefa?ade fa?ade提供了一 高层接口,这个使得子系统更容易用。
十九、 Proxy ProxyProxyProxy,代理模式:为其他对象提供一种以控制这个的访问
二十、 Adapter, Adapter,Adapter,Adapter,Adapter, Adapter,适配器模式:将一类的接口转换成客户希望另外个, 适配器模式:将一类的接口转换成客户希望另外个, 适配器模式:将一类的接口转换成客户希望另外个, 适配器模式:将一类的接口转换成客户希望另外个, 适配器模式:将一类的接口转换成客户希望另外个, 适配器模式:将一类的接口转换成客户希望另外个, 适配器模式:将一类的接口转换成客户希望另外个, 适配器模式:将一类的接口转换成客户希望另外个, 适配器模式:将一类的接口转换成客户希望另外个, 适配器模式:将一类的接口转换成客户希望另外个, 适配器模式:将一类的接口转换成客户希望另外个, 适配器模式:将一类的接口转换成客户希望另外个, 适配器模式:将一类的接口转换成客户希望另外个, 适配器模式:将一类的接口转换成客户希望另外个, 适配器模式:将一类的接口转换成客户希望另外个, 适配器模式:将一类的接口转换成客户希望另外个, 适配器模式:将一类的接口转换成客户希望另外个, 适配器模式:将一类的接口转换成客户希望另外个, 适配器模式:将一类的接口转换成客户希望另外个, 适配器模式:将一类的接口转换成客户希望另外个, 适配器模式:将一类的接口转换成客户希望另外个, 适配器模式:将一类的接口转换成客户希望另外个, 适配器模式:将一类的接口转换成客户希望另外个, 适配器模式:将一类的接口转换成客户希望另外个, Adapter AdapterAdapterAdapterAdapter 模式使得原本由于接口不兼容而能一起工作那些类可以。
二十一、 DecratorDecrator DecratorDecratorDecratorDecrator,装饰模式:动态地给一个对象增加 些额外的职责,就,装饰模式:动态地给一个对象增加 些额外的职责就,装饰模式:动态地给一个对象增加 些额外的职责就,装饰模式:动态地给一个对象增加 些额外的职责就,装饰模式:动态地给一个对象增加 些额外的职责就,装饰模式:动态地给一个对象增加 些额外的职责就,装饰模式:动态地给一个对象增加 些额外的职责就,装饰模式:动态地给一个对象增加 些额外的职责就,装饰模式:动态地给一个对象增加 些额外的职责就,装饰模式:动态地给一个对象增加 些额外的职责就,装饰模式:动态地给一个对象增加 些额外的职责就,装饰模式:动态地给一个对象增加 些额外的职责就,装饰模式:动态地给一个对象增加 些额外的职责就,装饰模式:动态地给一个对象增加 些额外的职责就,装饰模式:动态地给一个对象增加 些额外的职责就,装饰模式:动态地给一个对象增加 些额外的职责就,装饰模式:动态地给一个对象增加 些额外的职责就,装饰模式:动态地给一个对象增加 些额外的职责就,装饰模式:动态地给一个对象增加 些额外的职责就,装饰模式:动态地给一个对象增加 些额外的职责就,装饰模式:动态地给一个对象增加 些额外的职责就,装饰模式:动态地给一个对象增加 些额外的职责就,装饰模式:动态地给一个对象增加 些额外的职责就,装饰模式:动态地给一个对象增加 些额外的职责就,装饰模式:动态地给一个对象增加 些额外的职责就,装饰模式:动态地给一个对象增加 些额外的职责就,装饰模式:动态地给一个对象增加 些额外的职责就的功 能来说, DecoratorDecorator DecoratorDecoratorDecoratorDecoratorDecoratorDecorator模式相比生成子类更加灵活。 模式相比生成子类更加灵活。
二十、 BridgeBridge BridgeBridge,桥模式:将抽象部分与它的实现相离,使他们可以独立变 ,桥模式:将抽象部分与它的实现相离使他们可以独立变 ,桥模式:将抽象部分与它的实现相离使他们可以独立变 ,桥模式:将抽象部分与它的实现相离使他们可以独立变 ,桥模式:将抽象部分与它的实现相离使他们可以独立变 ,桥模式:将抽象部分与它的实现相离使他们可以独立变 ,桥模式:将抽象部分与它的实现相离使他们可以独立变 ,桥模式:将抽象部分与它的实现相离使他们可以独立变 ,桥模式:将抽象部分与它的实现相离使他们可以独立变 ,桥模式:将抽象部分与它的实现相离使他们可以独立变 ,桥模式:将抽象部分与它的实现相离使他们可以独立变 ,桥模式:将抽象部分与它的实现相离使他们可以独立变 ,桥模式:将抽象部分与它的实现相离使他们可以独立变 ,桥模式:将抽象部分与它的实现相离使他们可以独立变 ,桥模式:将抽象部分与它的实现相离使他们可以独立变 ,桥模式:将抽象部分与它的实现相离使他们可以独立变 ,桥模式:将抽象部分与它的实现相离使他们可以独立变 ,桥模式:将抽象部分与它的实现相离使他们可以独立变 ,桥模式:将抽象部分与它的实现相离使他们可以独立变 ,桥模式:将抽象部分与它的实现相离使他们可以独立变 ,桥模式:将抽象部分与它的实现相离使他们可以独立变 ,桥模式:将抽象部分与它的实现相离使他们可以独立变 ,桥模式:将抽象部分与它的实现相离使他们可以独立变 ,桥模式:将抽象部分与它的实现相离使他们可以独立变 ,桥模式:将抽象部分与它的实现相离使他们可以独立变 ,桥模式:将抽象部分与它的实现相离使他们可以独立变 ,桥模式:将抽象部分与它的实现相离使他们可以独立变 ,桥模式:将抽象部分与它的实现相离使他们可以独立变 ,桥模式:将抽象部分与它的实现相离使他们可以独立变 ,桥模式:将抽象部分与它的实现相离使他们可以独立变 化。
二十三、 Flyweight Flyweight Flyweight,享元模式
其实还有两类: 并发型模式和线程池。用一个图片来整体描述
二.设计模式的六大原则
总原则:开闭原则(Open Close Principle) 开闭原则就是说对扩展开放,对修改关闭。在程序需要进行拓展的时候,不能去修改原有的代码,而是要扩展原有代码,实现一个热插拔的效果。所以一句话概括就是:为了使程序的扩展性好,易于维护和升级。想要达到这样的效果,我们需要使用接口和抽象类等,后面的具体设计中我们会提到这点。
1、单一职责原则 不要存在多于一个导致类变更的原因,也就是说每个类应该实现单一的职责,如若不然,就应该把类拆分。
2、里氏替换原则(Liskov Substitution Principle) 里氏代换原则(Liskov Substitution Principle LSP)面向对象设计的基本原则之一。 里氏代换原则中说,任何基类可以出现的地方,子类一定可以出现。 LSP是继承复用的基石,只有当衍生类可以替换掉基类,软件单位的功能不受到影响时,基类才能真正被复用,而衍生类也能够在基类的基础上增加新的行为。里氏代换原则是对“开-闭”原则的补充。实现“开-闭”原则的关键步骤就是抽象化。而基类与子类的继承关系就是抽象化的具体实现,所以里氏代换原则是对实现抽象化的具体步骤的规范。—— From Baidu 百科 历史替换原则中,子类对父类的方法尽量不要重写和重载。因为父类代表了定义好的结构,通过这个规范的接口与外界交互,子类不应该随便破坏它。
3、依赖倒转原则(Dependence Inversion Principle) 这个是开闭原则的基础,具体内容:面向接口编程,依赖于抽象而不依赖于具体。写代码时用到具体类时,不与具体类交互,而与具体类的上层接口交互。
4、接口隔离原则(Interface Segregation Principle) 这个原则的意思是:每个接口中不存在子类用不到却必须实现的方法,如果不然,就要将接口拆分。使用多个隔离的接口,比使用单个接口(多个接口方法集合到一个的接口)要好。
5、迪米特法则(最少知道原则)(Demeter Principle)
就是说:一个类对自己依赖的类知道的越少越好。也就是说无论被依赖的类多么复杂,都应该将逻辑封装在方法的内部,通过public方法提供给外部。这样当被依赖的类变化时,才能最小的影响该类。 最少知道原则的另一个表达方式是:只与直接的朋友通信。类之间只要有耦合关系,就叫朋友关系。耦合分为依赖、关联、聚合、组合等。我们称出现为成员变量、方法参数、方法返回值中的类为直接朋友。局部变量、临时变量则不是直接的朋友。我们要求陌生的类不要作为局部变量出现在类中。
6、合成复用原则(Composite Reuse Principle) 原则是尽量首先使用合成/聚合的方式,而不是使用继承。
1、单例模式
单例对象(Singleton)是一种常用的设计模式。在Java应用中,单例对象能保证在一个JVM中,该对象只有一个实例存在。这样的模式有几个好处: 1、某些类创建比较频繁,对于一些大型的对象,这是一笔很大的系统开销。 2、省去了new操作符,降低了系统内存的使用频率,减轻GC压力。 3、有些类如交易所的核心交易引擎,控制着交易流程,如果该类可以创建多个的话,系统完全乱了。(比如一个军队出现了多个司令员同时指挥,肯定会乱成一团),所以只有使用单例模式,才能保证核心交易服务器独立控制整个流程。 首先我们写一个简单的单例类:
这个类可以满足基本要求,但是,像这样毫无线程安全保护的类,如果我们把它放入多线程的环境下,肯定就会出现问题了,如何解决?我们首先会想到对getInstance方法加synchronized关键字,如下:
但是,synchronized关键字锁住的是这个对象,这样的用法,在性能上会有所下降,因为每次调用getInstance(),都要对对象上锁,事实上,只有在第一次创建对象的时候需要加锁,之后就不需要了,所以,这个地方需要改进。我们改成下面这个:
似乎解决了之前提到的问题,将synchronized关键字加在了内部,也就是说当调用的时候是不需要加锁的,只有在instance为null,并创建对象的时候才需要加锁,性能有一定的提升。但是,这样的情况,还是有可能有问题的,看下面的情况:在Java指令中创建对象和赋值操作是分开进行的,也就是说instance = new Singleton();语句是分两步执行的。但是JVM并不保证这两个操作的先后顺序,也就是说有可能JVM会为新的Singleton实例分配空间,然后直接赋值给instance成员,然后再去初始化这个Singleton实例。这样就可能出错了,我们以A、B两个线程为例:
a>A、B线程同时进入了第一个if判断
b>A首先进入synchronized块,由于instance为null,所以它执行instance = new Singleton();
c>由于JVM内部的优化机制,JVM先画出了一些分配给Singleton实例的空白内存,并赋值给instance成员(注意此时JVM没有开始初始化这个实例),然后A离开了synchronized块。
d>B进入synchronized块,由于instance此时不是null,因此它马上离开了synchronized块并将结果返回给调用该方法的程序。 e>此时B线程打算使用Singleton实例,却发现它没有被初始化,于是错误发生了。 所以程序还是有可能发生错误,其实程序在运行过程是很复杂的,从这点我们就可以看出,尤其是在写多线程环境下的程序更有难度,有挑战性。我们对该程序做进一步优化:
实际情况是,单例模式使用内部类来维护单例的实现,JVM内部的机制能够保证当一个类被加载的时候,这个类的加载过程是线程互斥的。这样当我们第一次调用getInstance的时候,JVM能够帮我们保证instance只被创建一次,并且会保证把赋值给instance的内存初始化完毕,这样我们就不用担心上面的问题。同时该方法也只会在第一次调用的时候使用互斥机制,这样就解决了低性能问题。这样我们暂时总结一个完美的单例模式
其实说它完美,也不一定,如果在构造函数中抛出异常,实例将永远得不到创建,也会出错。所以说,十分完美的东西是没有的,我们只能根据实际情况,选择最适合自己应用场景的实现方法。也有人这样实现:因为我们只需要在创建类的时候进行同步,所以只要将创建和getInstance()分开,单独为创建加synchronized关键字,也是可以的:
通过单例模式的学习告诉我们: 1、单例模式理解起来简单,但是具体实现起来还是有一定的难度。 2、synchronized关键字锁定的是对象,在用的时候,一定要在恰当的地方使用(注意需要使用锁的对象和过程,可能有的时候并不是整个对象及整个过程都需要锁)。 到这儿,单例模式基本已经讲完了,结尾处,笔者突然想到另一个问题,就是采用类的静态方法,实现单例模式的效果,也是可行的,此处二者有什么不同? 首先,静态类不能实现接口。(从类的角度说是可以的,但是那样就破坏了静态了。因为接口中不允许有static修饰的方法,所以即使实现了也是非静态的) 其次,单例可以被延迟初始化,静态类一般在第一次加载是初始化。之所以延迟加载,是因为有些类比较庞大,所以延迟加载有助于提升性能。 再次,单例类可以被继承,他的方法可以被覆写。但是静态类内部方法都是static,无法被覆写。 最后一点,单例类比较灵活,毕竟从实现上只是一个普通的Java类,只要满足单例的基本需求,你可以在里面随心所欲的实现一些其它功能,但是静态类不行。从上面这些概括中,基本可以看出二者的区别,但是,从另一方面讲,我们上面最后实现的那个单例模式,内部就是用一个静态类来实现的,所以,二者有很大的关联,只是我们考虑问题的层面不同罢了。两种思想的结合,才能造就出完美的解决方案,就像HashMap采用数组+链表来实现一样,其实生活中很多事情都是这样,单用不同的方法来处理问题,总是有优点也有缺点,最完美的方法是,结合各个方法的优点,才能最好的解决问题!
2、动态代理
3、工厂模式
4、责任链模式