研磨设计模式之单例模式
设计模式:常用设计模式及其应用

设计模式:常用设计模式及其应用设计模式是在软件设计中常见问题的解决方案的一种反复使用的经验总结。
它们是已经被证明有效的经典解决方案,可以帮助我们在开发过程中避免重复设计。
本文将介绍一些常用的设计模式及其应用。
1.单例模式单例模式是一个创建型的设计模式,它会确保一个类只有一个实例。
这在需要共享资源或控制唯一资源访问的场景下非常实用,例如线程池、日志记录器等。
2.工厂模式工厂模式是一种用于创建对象的创建型设计模式。
它定义了一个接口来创建对象,但将创建实例的过程延迟到子类中。
这样可以避免在代码中直接使用new操作符,增加了代码的灵活性和可维护性。
3.观察者模式观察者模式是一种行为型的设计模式,它定义了一对多的依赖关系。
当一个对象的状态发生变化时,它会自动通知它的依赖对象。
观察者模式常用于事件处理、GUI编程等场景。
4.装饰器模式装饰器模式是一种结构型的设计模式,它允许你通过将对象包装在一个装饰器对象中来动态地添加新的功能。
装饰器模式可以避免使用子类化的复杂性,提供了比继承更加灵活的方式来扩展功能。
5.策略模式策略模式是一种行为型的设计模式,它定义了一系列算法,并将每个算法封装在可以相互替换的策略对象中。
这使得算法可以独立于客户端的使用,提高了代码的灵活性。
6.适配器模式适配器模式是一种结构型的设计模式,它允许不兼容的接口之间进行适配。
适配器模式可以通过创建一个适配器类来实现两个不兼容接口之间的交互。
7. MVC模式MVC(Model-View-Controller)是一种架构模式,它将应用程序分为三个主要部分:模型、视图和控制器。
模型表示应用程序的数据和逻辑,视图负责显示数据,控制器接收用户输入并对模型和视图进行协调。
8.组合模式组合模式是一种结构型的设计模式,它将对象组合成树状结构以表示“整体/部分”层次结构。
组合模式使得用户对单个对象和组合对象的使用具有一致性,可以用来处理树形结构的问题。
9.迭代器模式迭代器模式是一种行为型的设计模式,它提供一种访问容器中各个元素的方法,而不需要暴露容器的内部结构。
单例模式的优缺点和使用场景

3.单例类的职责过重,在一定程度上违背了“单一职责原则”。
4.滥用单例将带来一些负面问题,如为了节省资源将数据库连接池对象设计为的单例类,可能会导致共享连接池对象的程序过多而出现连接池溢出;如果实例化的对象长时间不被利用,系统会认为是垃圾而被回收,这将导致对象状态的丢失。
3.双重检测
class Test {
private Test() {
}
public static Test instance = null;
public static Test getInstance() {
if (instance == null) {
}
return instance;
}
}
优点:
避免了饿汉式的那种在没有用到的情况下创建事例,资源利用率高,不执行getInstance()就不会被实例,可以执行该类的其他静态方法。
缺点:
懒汉式在单个线程中没有问题,但多个线程同事访问的时候就可能同事创建多个实例,而且这多个实例不是同一个对象,虽然后面创建的实例会覆盖先创建的实例,但是还是会存在拿到不同对象的情况。解决这个问题的办法就是加锁synchonized,第一次加载时不够快,多线程使用不必要的同步开销大。
1.需要频繁实例化然后销毁的对象。
2.创建对象时耗时过多或者耗资源过多,但又经常用到的对象。
3.有状态的工具类对象。
4.频繁访问数据库或文件的对象。
以下都是单例模式的经典使用场景:
1.资源共享的情况下,避免由于资源操作时导致的性能或损耗等。如上述中的日志文件,应用配置。
}
Java设计模式之《单例模式》及应用场景

Java设计模式之《单例模式》及应⽤场景所谓单例,指的就是单实例,有且仅有⼀个类实例,这个单例不应该由⼈来控制,⽽应该由代码来限制,强制单例。
单例有其独有的使⽤场景,⼀般是对于那些业务逻辑上限定不能多例只能单例的情况,例如:类似于计数器之类的存在,⼀般都需要使⽤⼀个实例来进⾏记录,若多例计数则会不准确。
其实单例就是那些很明显的使⽤场合,没有之前学习的那些模式所使⽤的复杂场景,只要你需要使⽤单例,那你就使⽤单例,简单易理解。
所以我认为有关单例模式的重点不在于场景,⽽在于如何使⽤。
1、常见的单例模式有两种创建⽅式:所谓饿懒汉式与饿汉式(1)懒汉式 何为懒?顾名思义,就是不做事,这⾥也是同义,懒汉式就是不在系统加载时就创建类的单例,⽽是在第⼀次使⽤实例的时候再创建。
详见下⽅代码⽰例:public class LHanDanli {//定义⼀个私有类变量来存放单例,私有的⽬的是指外部⽆法直接获取这个变量,⽽要使⽤提供的公共⽅法来获取private static LHanDanli dl = null;//定义私有构造器,表⽰只在类内部使⽤,亦指单例的实例只能在单例类内部创建private LHanDanli(){}//定义⼀个公共的公开的⽅法来返回该类的实例,由于是懒汉式,需要在第⼀次使⽤时⽣成实例,所以为了线程安全,使⽤synchronized关键字来确保只会⽣成单例public static synchronized LHanDanli getInstance(){if(dl == null){dl = new LHanDanli();}return dl;}}(2)饿汉式 ⼜何为饿?饿者,饥不择⾷;但凡有⾷,必急⾷之。
此处同义:在加载类的时候就会创建类的单例,并保存在类中。
详见下⽅代码⽰例:public class EHanDanli {//此处定义类变量实例并直接实例化,在类加载的时候就完成了实例化并保存在类中private static EHanDanli dl = new EHanDanli();//定义⽆参构造器,⽤于单例实例private EHanDanli(){}//定义公开⽅法,返回已创建的单例public static EHanDanli getInstance(){return dl;}}2、双重加锁机制 何为双重加锁机制? 在懒汉式实现单例模式的代码中,有使⽤synchronized关键字来同步获取实例,保证单例的唯⼀性,但是上⾯的代码在每⼀次执⾏时都要进⾏同步和判断,⽆疑会拖慢速度,使⽤双重加锁机制正好可以解决这个问题:public class SLHanDanli {private static volatile SLHanDanli dl = null;private SLHanDanli(){}public static SLHanDanli getInstance(){if(dl == null){synchronized (SLHanDanli.class) {if(dl == null){dl = new SLHanDanli();}}}return dl;}}看了上⾯的代码,有没有感觉很⽆语,双重加锁难道不是需要两个synchronized进⾏加锁的吗? ...... 其实不然,这⾥的双重指的的双重判断,⽽加锁单指那个synchronized,为什么要进⾏双重判断,其实很简单,第⼀重判断,如果单例已经存在,那么就不再需要进⾏同步操作,⽽是直接返回这个实例,如果没有创建,才会进⼊同步块,同步块的⽬的与之前相同,⽬的是为了防⽌有两个调⽤同时进⾏时,导致⽣成多个实例,有了同步块,每次只能有⼀个线程调⽤能访问同步块内容,当第⼀个抢到锁的调⽤获取了实例之后,这个实例就会被创建,之后的所有调⽤都不会进⼊同步块,直接在第⼀重判断就返回了单例。
java单例和多例的使用场景

Java单例和多例的使用场景1. 引言在Java编程中,单例(Singleton)和多例(Multiton)是两种常用的设计模式。
它们都用于控制对象的创建和访问,但在不同的场景下有不同的应用。
本文将深入探讨Java单例和多例的使用场景,包括对其定义、特点以及适用的具体情况进行详细说明,并举例说明其在实际开发中的应用。
2. 单例模式2.1 定义与特点单例模式是一种创建型设计模式,它确保一个类只有一个实例,并提供一个全局访问点。
单例模式的主要特点包括:•一个类只有一个实例对象;•类自行实例化,并对外提供访问该实例的静态方法;•防止其他对象创建该类的实例。
2.2 使用场景单例模式适用于以下情况:•系统中只需要一个实例对象,例如配置文件、日志记录器等。
•需要频繁创建和销毁对象的场景,为了节省系统资源,避免频繁的创建和销毁对象,可以使用单例模式。
•需要全局访问点来访问实例对象,例如线程池、数据库连接池等。
2.3 实例应用2.3.1 配置文件读取器在大多数应用程序中,都需要读取配置文件来获取系统配置信息。
使用单例模式可以确保配置文件读取器只有一个实例,避免重复读取配置文件,提高性能。
public class ConfigReader {private static ConfigReader instance;private Properties properties;private ConfigReader() {properties = new Properties();// 读取配置文件try {properties.load(new FileInputStream("config.properties"));} catch (IOException e) {e.printStackTrace();}}public static ConfigReader getInstance() {if (instance == null) {synchronized (ConfigReader.class) {if (instance == null) {instance = new ConfigReader();}}}return instance;}public String getProperty(String key) {return properties.getProperty(key);}}2.3.2 日志记录器在日志记录的场景中,单例模式也经常被使用。
单例模式和工厂模式的区别

单例模式和工厂模式的区别在软件开发领域中,设计模式是一种被广泛应用的理论,它解决了各种软件开发领域中的重要问题。
其中,单例模式和工厂模式作为两种常见的设计模式,对于软件开发者来说是非常重要的。
尽管两种模式都是为了解决类对象创建的问题,但它们的设计理念和实现方法却完全不同,本文将重点讨论单例模式和工厂模式的区别。
单例模式单例模式是一种常用的设计模式,用于表示一个类仅仅创建一个实例。
也就是说,如果两个变量具有同样的类和相同的属性,它们实际上是同一个实例。
这样可以避免内存浪费、提高性能并固定对象实例的状态。
在单例模式中,类的构造函数是私有的,也就是说,无法从外部创建新的实例。
由类的静态方法控制创建类的实例,并确保始终只有一个实例被创建和使用。
在实际应用中,单例模式通常被用于维护系统中唯一一个资源或全局对象,如高频访问的配置单例对象或日志单例对象等。
在多线程环境中,为确保单例实例的正确性和安全性,单例模式需要进行更加复杂的设计和实现,如CAS、锁等机制。
工厂模式工厂模式是一种常见的设计模式,它是一种创建型模式。
与单例模式不同,工厂模式解决的是面向对象编程中对象的创建问题。
在工厂模式中,为了实现更加灵活和方便的对象创建方式,我们使用相应的工厂类来封装对象的创建方法,而工厂类的实例化方法则可以根据实际需要进行灵活变化。
工厂模式的主要特点是:在工厂模式中,客户端代码面向抽象工厂接口编程,而不是面向具体产品类编程。
在定义抽象工厂接口时,一般的做法是:定义工厂方法模板,并声明一个返回值为抽象产品的方法,如:```public interface Factory {public Product createProduct();}```由不同的具体工厂类来继承抽象工厂接口,从而实现具体产品的创建。
单例模式和工厂模式的区别尽管单例模式和工厂模式都是创建型模式,它们的适用范围和实现机制完全不同。
下面我们将从三个维度来分析两种设计模式的区别。
单例模式如何确保一个类只有一个实例

单例模式如何确保一个类只有一个实例单例模式是一种常用的设计模式,用于确保一个类只有一个实例。
在许多应用场景中,只需要一个对象来完成某些任务,而不需要多个实例。
单例模式提供了一种简洁的方案,可以保证整个程序中只存在一个特定类的实例,避免了多个实例引发的问题。
1. 概述单例模式的核心思想是通过限制实例的创建和访问来确保一个类只有一个实例。
常见的实现方式有饿汉式和懒汉式两种。
2. 饿汉式单例模式饿汉式单例模式是指在类加载的时候就创建实例,因此实例的创建是立即发生的。
在类加载时,静态变量会被初始化,因此可以保证只有一个实例。
```javapublic class Singleton {private static Singleton instance = new Singleton();// 私有化构造方法private Singleton() {}public static Singleton getInstance() {return instance;}}```3. 懒汉式单例模式懒汉式单例模式是指实例的创建延迟到第一次使用时才进行。
在多线程环境下,需要考虑线程安全的问题。
以下是一种线程安全的懒汉式单例模式实现方式:```javapublic class Singleton {private static volatile Singleton instance;// 私有化构造方法private Singleton() {}public static Singleton getInstance() {if (instance == null) {synchronized (Singleton.class) {if (instance == null) {instance = new Singleton();}}}return instance;}}```4. 枚举单例模式Java中的枚举类型本身就是单例的,因为枚举类型的实例只能有限个,而且在任何情况下都是线程安全的。
单例的七种写法
单例的七种写法单例模式是一种常用的设计模式,它保证一个类只有一个实例,并提供一个全局访问点。
在实际开发中,我们经常会遇到需要使用单例模式的场景。
在Java中,单例模式有七种写法,下面我们来逐一介绍。
1. 饿汉式单例模式饿汉式单例模式指的是在类加载时就实例化了该类的唯一实例。
这种写法没有使用锁,因此线程安全。
代码如下:```public class Singleton {private static final Singleton instance = new Singleton();private Singleton() {}public static Singleton getInstance() {return instance;}}```2. 懒汉式单例模式懒汉式单例模式指的是在第一次使用时才实例化该类的唯一实例。
这种写法需要使用同步锁,因此效率较低。
代码如下:```public class Singleton {private static Singleton instance;private Singleton() {}public static synchronized Singleton getInstance() {if (instance == null) {instance = new Singleton();}return instance;}}```3. 双重校验锁单例模式双重校验锁单例模式指的是先判断实例是否存在,若不存在,则进入同步块进行实例化,提高效率。
这种写法需要使用volatile修饰实例,保证线程安全。
代码如下:public class Singleton {private static volatile Singleton instance;private Singleton() {}public static Singleton getInstance() {if (instance == null) {synchronized (Singleton.class) {if (instance == null) {instance = new Singleton();}}}return instance;}}```4. 静态内部类单例模式静态内部类单例模式指的是利用静态内部类的加载机制实现单例。
java常用的设计模式及应用场景
java常用的设计模式及应用场景一、单例模式(Singleton)单例模式是一种对象创建型模式,它指的是设计一个类,使其只能生成一个实例。
它只提供一个类实例,保证只有一个实例存在。
有时候,只需要一个类的实例来控制整个系统,例如实现一个全局的缓存,或是建立一个共享的日志记录器,单例模式可以很好的实现这个目的。
应用场景:1、对于需要频繁创建和销毁的对象,可以考虑使用单例模式,以避免过多地重复创建和销毁造成系统开销。
2、对于某些资源比较宝贵的对象,例如数据库连接,则可以用单例模式进行封装,保证全局应用程序只有一个,从而避免重复创建,浪费资源。
二、工厂模式(Factory)工厂模式是一种类创建型模式,它把类的实例化推迟到子类来完成。
它用于隔离客户类和实例化对象,通过声明抽象类类来定义构造过程,将不同的定义转移到不同的子类中去,从而使用户不需要关心实例化过程。
1、在有大量不同对象需要创建和管理的情况下,可以利用工厂模式封装类的实例化和存储,将池中不同对象来进行统一管理。
2、在使用设计模式的情况下,复杂的类结构已经不适合用一个实例来创建,可以采用工厂模式实现多个类的实例化,让用户不用关心对象实例的创建过程。
抽象工厂模式是一种工厂模式的拓展,它把简单工厂模式的单一职责拆分为多个类,从而实现一个系列相关的或相互依赖的工厂,以满足比较复杂的对象创建需求。
1、在需要创建复杂对象,而复杂对象又由多个部件组成的情况下,例如计算机,单一工厂模式已经不能满足需求,那么可以通过抽象工厂模式来实现。
2、在需要产生大量不同类型的对象,或者存在一系列相互依赖的产品族,这种情况下可以使用抽象工厂模式,将工厂定义为不同维度组成的一个系列。
四、建造者模式(Builder)建造者模式是一种设计模式,它也叫构造子模式,通过使用建造者模式,客户端可以不必担心具体的生产过程,只需要给出具体的请求,由建造者来负责构造出请求的产品对象。
1、在有复杂的产品对象的时候,例如需要对多个部件进行拼装,以构造出复杂的对象,可以采用建造者模式将复杂的拼装过程进行封装,避免复杂的拼装过程变得混乱。
23种设计模式范文
23种设计模式范文设计模式是软件开发中常用的解决方案模式,它们代表了在面对特定问题时的最佳实践和经验总结。
设计模式可以帮助我们更好地组织和设计代码,提高代码的可读性、可维护性和可扩展性。
在本文中,我们将介绍23种常用的设计模式,并分别讨论它们的实现原理和在实际开发中的应用场景。
1. 单例模式(Singleton Pattern)单例模式是最简单的设计模式之一,它确保一个类只有一个实例,并提供一个全局访问点。
在实现上,可以通过将构造函数私有化,然后提供一个静态方法返回实例来实现单例。
应用场景:在需要实现全局唯一访问点的场景下,比如线程池、配置管理器等。
2. 工厂模式(Factory Pattern)工厂模式是用来创建对象的一种模式,它将对象的创建和实现分离,使得代码更易于维护和扩展。
工厂模式有简单工厂模式、工厂方法模式和抽象工厂模式等几种不同的变体。
应用场景:在需要根据不同条件创建不同对象的场景下,比如数据库连接、日志记录等。
3. 抽象工厂模式(Abstract Factory Pattern)抽象工厂模式是工厂模式的一种扩展,它提供一个创建一系列相关或相互依赖对象的接口,而无需指定实际的类。
抽象工厂模式将一组工厂类封装起来,使其可以交换或者替换。
应用场景:在需要创建一组相关对象(如界面主题、操作系统等)并且需要保持一致性的场景下。
4. 建造者模式(Builder Pattern)建造者模式是用来生成复杂对象的一种模式,它将对象的构建与其表现分离,采用逐步构建的方式生成对象,可以让客户端不需要知道具体的构建细节。
应用场景:在构造过程比较复杂,需要多个组件协同工作的场景下,比如构建复杂的UI界面。
5. 原型模式(Prototype Pattern)原型模式是用来克隆对象的一种模式,它通过复制已有对象的原型来创建新的对象,避免了通过构造函数创建对象和初始化成员变量的重复过程。
应用场景:在需要创建大量相似对象或者初始化成本较高的对象时,可以使用原型模式。
Spring中常见的设计模式——单例模式
Spring中常见的设计模式——单例模式⼀、单例模式的应⽤场景 单例模式(singleton Pattern)是指确保⼀个类在任何情况下都绝对只有⼀个实例,并提供⼀个全局访问点。
J2EE中的ServletContext,ServletContextConfig等;Spring中的ApplicationContext、数据库连接池等。
⼆、饿汉式单例模式 饿汉式单例模式在类加载的时候就⽴即初始化,并且创建单例对象。
它是绝对的线程安全、在线程还没出现以前就实现了,不可能存在访问安全问题。
优点:没有增加任何锁,执⾏效率⾼,⽤户体验⽐懒汉式好。
缺点:类加载的时候就初始化了,⽤不⽤都进⾏,浪费内存。
Spring 中IoC容器ApplocationContext本⾝就是典型的饿汉式单例模式:public class HungrySingleton {private static final HungrySingleton h = new HungrySingleton();private HungrySingleton() {}public static HungrySingleton getInstance() {return h;}} 饿汉式单例模式适⽤于单例对象较少的情况。
三、懒汉式单例模式 被外部调⽤才会加载:public class LazySimpleSingleton {private LazySimpleSingleton() {}private static LazySimpleSingleton lazy = null;public static LazySimpleSingleton getInstance() {if (lazy == null) {lazy = new LazySimpleSingleton();}return lazy;}}利⽤线程创建实例:public class ExectorThread implements Runnable {@Overridepublic void run() {LazySimpleSingleton simpleSingleton = LazySimpleSingleton.getInstance();System.out.println(Thread.currentThread().getName() + ":" + simpleSingleton);}}客户端代码:public class LazySimpleSingletonTest {public static void main(String[] args) {Thread t1 = new Thread(new ExectorThread());Thread t2 = new Thread(new ExectorThread());t1.start();t2.start();System.out.println("END");}}结果:ENDThread-1:zySimpleSingleton@298c37fdThread-0:zySimpleSingleton@6ebc1cfd可以看到产⽣的两个实例的内存地址不同说明产⽣了两个实例,⼤家可以通过以下打断点的⽅式实现不同Thread运⾏状态见进⾏切换。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
单例模式(Singleton)1 场景问题1.1 读取配置文件的内容考虑这样一个应用,读取配置文件的内容。
很多应用项目,都有与应用相关的配置文件,这些配置文件多是由项目开发人员自定义的,在里面定义一些应用需要的参数数据。
当然在实际的项目中,这种配置文件多采用xml格式的。
也有采用properties格式的,毕竟使用Java 来读取properties格式的配置文件比较简单。
现在要读取配置文件的内容,该如何实现呢?1.2 不用模式的解决方案有些朋友会想,要读取配置文件的内容,这也不是个什么困难的事情,直接读取文件的内容,然后把文件内容存放在相应的数据对象里面就可以了。
真的这么简单吗?先实现看看吧。
为了示例简单,假设系统是采用的properties格式的配置文件。
(1)那么直接使用Java来读取配置文件,示例代码如下:/*** 读取应用配置文件*/public class AppConfig {/*** 用来存放配置文件中参数A的值*/private String parameterA;/*** 用来存放配置文件中参数B的值*/private String parameterB;public String getParameterA() {return parameterA;}public String getParameterB() {return parameterB;}/*** 构造方法*/public AppConfig(){//调用读取配置文件的方法readConfig();}/*** 读取配置文件,把配置文件中的内容读出来设置到属性上*/private void readConfig(){Properties p = new Properties();InputStream in = null;try {in = AppConfig.class.getResourceAsStream( "AppConfig.properties");p.load(in);//把配置文件中的内容读出来设置到属性上this.parameterA = p.getProperty("paramA");this.parameterB = p.getProperty("paramB");} catch (IOException e) {System.out.println("装载配置文件出错了,具体堆栈信息如下:");e.printStackTrace();}finally{try {in.close();} catch (IOException e) {e.printStackTrace();}}}}注意:只有访问参数的方法,没有设置参数的方法。
(2)应用的配置文件,名字是AppConfig.properties,放在AppConfig相同的包里面,简单示例如下:paramA=aparamB=b(3)写个客户端来测试一下,示例代码如下:public class Client {public static void main(String[] args) {//创建读取应用配置的对象AppConfig config = new AppConfig();String paramA = config.getParameterA();String paramB = config.getParameterB();System.out.println("paramA="+paramA+",paramB="+paramB);}}运行结果如下:paramA=a,paramB=b1.3 有何问题上面的实现很简单嘛,很容易的就实现了要求的功能。
仔细想想,有没有什么问题呢?看看客户端使用这个类的地方,是通过new一个AppConfig的实例来得到一个操作配置文件内容的对象。
如果在系统运行中,有很多地方都需要使用配置文件的内容,也就是很多地方都需要创建AppConfig这个对象的实例。
换句话说,在系统运行期间,系统中会存在很多个AppConfig的实例对象,这有什么问题吗?当然有问题了,试想一下,每一个AppConfig实例对象,里面都封装着配置文件的内容,系统中有多个AppConfig实例对象,也就是说系统中会同时存在多份配置文件的内容,这会严重浪费内存资源。
如果配置文件内容较少,问题还小一点,如果配置文件内容本来就多的话,对于系统资源的浪费问题就大了。
事实上,对于AppConfig这种类,在运行期间,只需要一个实例对象就够了。
把上面的描述进一步抽象一下,问题就出来了:在一个系统运行期间,某个类只需要一个类实例就可以了,那么应该怎么实现呢?2 解决方案2.1 单例模式来解决用来解决上述问题的一个合理的解决方案就是单例模式。
那么什么是单例模式呢?(1)单例模式定义保证一个类仅有一个实例,并提供一个访问它的全局访问点。
(2)应用单例模式来解决的思路仔细分析上面的问题,现在一个类能够被创建多个实例,问题的根源在于类的构造方法是公开的,也就是可以让类的外部来通过构造方法创建多个实例。
换句话说,只要类的构造方法能让类的外部访问,就没有办法去控制外部来创建这个类的实例个数。
要想控制一个类只被创建一个实例,那么首要的问题就是要把创建实例的权限收回来,让类自身来负责自己类实例的创建工作,然后由这个类来提供外部可以访问这个类实例的方法,这就是单例模式的实现方式。
2.2 模式结构和说明单例模式结构见图1所:图1 单例模式结构图Singleton:负责创建Singleton类自己的唯一实例,并提供一个getInstance的方法,让外部来访问这个类的唯一实例。
2.3 单例模式示例代码在Java中,单例模式的实现又分为两种,一种称为懒汉式,一种称为饿汉式,其实就是在具体创建对象实例的处理上,有不同的实现方式。
下面分别来看这两种实现方式的代码示例。
为何这么写,具体的在后面再讲述。
(1)懒汉式实现,示例代码如下:/*** 懒汉式单例实现的示例*/public class Singleton {/*** 定义一个变量来存储创建好的类实例*/private static Singleton uniqueInstance = null;/*** 私有化构造方法,好在内部控制创建实例的数目*/private Singleton(){//}/*** 定义一个方法来为客户端提供类实例* @return 一个Singleton的实例*/public static synchronized Singleton getInstance(){//判断存储实例的变量是否有值if(uniqueInstance == null){//如果没有,就创建一个类实例,并把值赋值给存储类实例的变量uniqueInstance = new Singleton();}//如果有值,那就直接使用return uniqueInstance;}/*** 示意方法,单例可以有自己的操作*/public void singletonOperation(){//功能处理}/*** 示意属性,单例可以有自己的属性*/private String singletonData;/*** 示意方法,让外部通过这些方法来访问属性的值* @return 属性的值*/public String getSingletonData(){return singletonData;}}(2)饿汉式实现,示例代码如下:/*** 饿汉式单例实现的示例*/public class Singleton {/*** 定义一个变量来存储创建好的类实例,直接在这里创建类实例,只会创建一次*/private static Singleton uniqueInstance = new Singleton();/*** 私有化构造方法,好在内部控制创建实例的数目*/private Singleton(){//}/*** 定义一个方法来为客户端提供类实例* @return 一个Singleton的实例*/public static Singleton getInstance(){//直接使用已经创建好的实例return uniqueInstance;}/*** 示意方法,单例可以有自己的操作*/public void singletonOperation(){//功能处理}* 示意属性,单例可以有自己的属性*/private String singletonData;/*** 示意方法,让外部通过这些方法来访问属性的值* @return 属性的值*/public String getSingletonData(){return singletonData;}}2.4 使用单例模式重写示例要使用单例模式来重写示例,由于单例模式有两种实现方式,这里选一种来实现就好了,就选择饿汉式的实现方式来重写示例吧。
采用饿汉式的实现方式来重写实例的示例代码如下:/*** 读取应用配置文件,单例实现*/public class AppConfig {/*** 定义一个变量来存储创建好的类实例,直接在这里创建类实例,只会创建一次*/private static AppConfig instance = new AppConfig();/*** 定义一个方法来为客户端提供AppConfig类的实例* @return 一个AppConfig的实例*/public static AppConfig getInstance(){return instance;}/*** 用来存放配置文件中参数A的值*/private String parameterA;/*** 用来存放配置文件中参数B的值private String parameterB;public String getParameterA() {return parameterA;}public String getParameterB() {return parameterB;}/*** 私有化构造方法*/private AppConfig(){//调用读取配置文件的方法readConfig();}/*** 读取配置文件,把配置文件中的内容读出来设置到属性上*/private void readConfig(){Properties p = new Properties();InputStream in = null;try {in = AppConfig.class.getResourceAsStream( "AppConfig.properties");p.load(in);//把配置文件中的内容读出来设置到属性上this.parameterA = p.getProperty("paramA");this.parameterB = p.getProperty("paramB");} catch (IOException e) {System.out.println("装载配置文件出错了,具体堆栈信息如下:");e.printStackTrace();}finally{try {in.close();} catch (IOException e) {e.printStackTrace();}}}}当然,测试的客户端也需要相应的变化,示例代码如下:public class Client {public static void main(String[] args) {//创建读取应用配置的对象AppConfig config = AppConfig.getInstance();String paramA = config.getParameterA();String paramB = config.getParameterB();System.out.println("paramA="+paramA+",paramB="+paramB);}}去测试看看,是否能满足要求。