基于java的单例模型和工厂模式

一、单例模型

(一) 定义

单例模型:指一个类只有一个实例,且该类能自行创建这个实例的一种模式。基于java的单例模型和工厂模式

(二)实现方式

常见的实现方式有:懒汉模式、饥汉模式、双重校验锁、静态内部类、枚举等方式实现

注意:
1、单例类只能有一个实例。
2、单例类必须自己创建自己的唯一实例。
3、单例类必须给所有其他对象提供这一实例。

(三)优缺点

1.优点:

(1)在内存里只有一个实例,减少了内存的开销,尤其是频繁的创建和销毁实例(比如管理学院首页页面缓存)。
2、避免对资源的多重占用(比如写文件操作)。

2.缺点

没有接口,不能继承,与单一职责原则冲突,一个类应该只关心内部逻辑,而不关心外面怎么样来实例化。

(四)使用场景

(1)要求生产唯一序列号。
(2)WEB 中的计数器,不用每次刷新都在数据库里加一次,用单例先缓存起来。
(3)创建的一个对象需要消耗的资源过多,比如 I/O 与数据库的连接等。

(五)实现

创建一个 SingleObject 类。SingleObject 类有它的私有构造函数和本身的一个静态实例。
SingleObject 类提供了一个静态方法,供外界获取它的静态实例。SingletonPatternDemo 类使用 SingleObject 类来获取 SingleObject 对象。
在这里插入图片描述
1.新建Java项目,在java项目下新建包,在该包下新建类
在这里插入图片描述

2.创建 SingleObject 类

package simple;

public class SingleObject {
    //创建 SingleObject 的一个对象
    private static SingleObject instance = new SingleObject();

    //让构造函数为 private,这样该类就不会被实例化
    private SingleObject(){}

    //获取唯一可用的对象
    public static SingleObject getInstance(){
        return instance;
    }

    public void showMessage(){
        System.out.println("Hello World!");
    }
}

3.创建SingletonPatternDemo类, 从singleObject 类获取唯一的对象

package simple;

public class SingletonPatternDemo {
    public static void main(String[] args) {

        //不合法的构造函数
        //编译时错误:构造函数 SingleObject() 是不可见的
        //SingleObject object = new SingleObject();

        //获取唯一可用的对象
        SingleObject object = SingleObject.getInstance();

        //显示消息
        object.showMessage();
    }
}

4.点击SingletonPatternDemo右键,run"SSingletonPatternDemo…"在这里插入图片描述
5.结果
在这里插入图片描述

(六)单例模型的几种实现方式

1.懒汉式,线程不安全

(1)概述
名称功能
是否 Lazy 初始化
是否多线程安全
实现难度

描述:这种方式是最基本的实现方式,这种实现最大的问题就是不支持多线程。因为没有加锁 synchronized,所以严格意义上它并不算单例模式。
这种方式 lazy loading 很明显,不要求线程安全,在多线程不能正常工作。

(2)实现方式
package simple;

public class Singleton {
    private static Singleton instance;
    private Singleton (){}

    public static Singleton getInstance() {
        if (instance == null) {
            instance = new Singleton();
        }
        return instance;
    }
}

2.懒汉式,线程安全

(1)概述
名称功能
是否 Lazy 初始化
是否多线程安全
实现难度

描述:这种方式具备很好的 lazy loading,能够在多线程中很好的工作,但是,效率很低,99% 情况下不需要同步。

(2)优缺点

优点:第一次调用才初始化,避免内存浪费。
缺点:必须加锁 synchronized 才能保证单例,但加锁会影响效率。
getInstance() 的性能对应用程序不是很关键(该方法使用不太频繁)。

(3)实例

1.新建Singleton类
在这里插入图片描述

package simple;

public class Singleton {
    private static Singleton instance;
    private Singleton (){}

    public static Singleton getInstance() {
        if (instance == null) {
            instance = new Singleton();
        }
        return instance;
    }

}

2.修改SingletonPatternDemo类

package simple;

public class SingletonPatternDemo {
    public static void main(String[] args) {

        //不合法的构造函数
        //编译时错误:构造函数 SingleObject() 是不可见的
        //SingleObject object = new SingleObject();

        //获取唯一可用的对象
        Singleton object = Singleton.getInstance();

    }
}

3.运行
在这里插入图片描述

3.饿汉式

(1)概述
名称功能
是否 Lazy 初始化
是否多线程安全
实现难度

描述:这种方式比较常用,但容易产生垃圾对象。

(2)优缺点

优点:没有加锁,执行效率会提高。
缺点:类加载时就初始化,浪费内存。

(3) 实例
public class Singleton {  
    private static Singleton instance = new Singleton();  
    private Singleton (){}  
    public static Singleton getInstance() {  
    return instance;  
    }  

4.双检锁/双重校验锁

(1)概述
名称功能
JDK 版本JDK1.5 起
是否 Lazy 初始化
是否多线程安全
实现难度较复杂

描述:这种方式采用双锁机制,安全且在多线程情况下能保持高性能。
getInstance() 的性能对应用程序很关键。

(2) 实例
public class Singleton {  
    private volatile static Singleton singleton;  
    private Singleton (){}  
    public static Singleton getSingleton() {  
    if (singleton == null) {  
        synchronized (Singleton.class) {  
        if (singleton == null) {  
            singleton = new Singleton();  
        }  
        }  
    }  
    return singleton;  
    }  
}

5.登记式/静态内部类

(1)概述
名称功能
是否 Lazy 初始化
是否多线程安全
实现难度一般

描述:这种方式能达到双检锁方式一样的功效,但实现更简单。对静态域使用延迟初始化,应使用这种方式而不是双检锁方式。这种方式只适用于静态域的情况,双检锁方式可在实例域需要延迟初始化时使用。

(3) 实例
public class Singleton {  
    private static class SingletonHolder {  
    private static final Singleton INSTANCE = new Singleton();  
    }  
    private Singleton (){}  
    public static final Singleton getInstance() {  
    return SingletonHolder.INSTANCE;  
    }  
}

6.枚举

(1)概述
名称功能
JDK 版本JDK1.5 起
是否 Lazy 初始化
是否多线程安全
实现难度
(3) 实例
public enum Singleton {  
    INSTANCE;  
    public void whateverMethod() {  
    }  
}

二、工厂模式

(一)概述

工厂模式(Factory Pattern)是 Java 中最常用的设计模式之一。这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。

在工厂模式中,我们在创建对象时不会对客户端暴露创建逻辑,并且是通过使用一个共同的接口来指向新创建的对象。

(二)介绍

名称功能方式
意图定义一个创建对象的接口,让其子类自己决定实例化哪一个工厂类,工厂模式使其创建过程延迟到子类进行。
主要解决主要解决接口选择的问题
使用时间我们明确地计划不同条件下创建不同实例时
解决方法让其子类实现工厂接口,返回的也是一个抽象的产品。
关键代码创建过程在其子类执行

(三)优缺点

1.优点

(1)一个调用者想创建一个对象,只要知道其名称就可以了。
(2)扩展性高,如果想增加一个产品,只要扩展一个工厂类就可以。
(3)屏蔽产品的具体实现,调用者只关心产品的接口。

2.缺点

每次增加一个产品时,都需要增加一个具体类和对象实现工厂,使得系统中类的个数成倍增加,在一定程度上增加了系统的复杂度,同时也增加了系统具体类的依赖。这并不是什么好事。

(四)使用场景

1.日志记录器:记录可能记录到本地硬盘、系统事件、远程服务器等,用户可以选择记录日志到什么地方。
2.数据库访问,当用户不知道最后系统采用哪一类数据库,以及数据库可能有变化时。
3.设计一个连接服务器的框架,需要三个协议,“POP3”、“IMAP”、“HTTP”,可以把这三个作为产品类,共同实现一个接口。

(五)注意事项

作为一种创建类模式,在任何需要生成复杂对象的地方,都可以使用工厂方法模式。有一点需要注意的地方就是复杂对象适合使用工厂模式,而简单对象,特别是只需要通过 new 就可以完成创建的对象,无需使用工厂模式。如果使用工厂模式,就需要引入一个工厂类,会增加系统的复杂度

(六)实现

我们将创建一个 Shape 接口和实现 Shape 接口的实体类。下一步是定义工厂类 ShapeFactory。

FactoryPatternDemo 类使用 ShapeFactory 来获取 Shape 对象。它将向 ShapeFactory 传递信息(CIRCLE / RECTANGLE / SQUARE),以便获取它所需对象的类型。

在这里插入图片描述

(七)简单工厂模型

1.概念

我们把被创建的对象称为“产品”,把创建产品的对象称为“工厂”。如果要创建的产品不多,只要一个工厂类就可以完成,这种模式叫“简单工厂模式”。

在简单工厂模式中创建实例的方法通常为静态(static)方法

因此简单工厂模式(Simple Factory Pattern)又叫作静态工厂方法模式(Static Factory Method Pattern)。

2.简单工厂模型的组成

(1)简单工厂(SimpleFactory):是简单工厂模式的核心,负责实现创建所有实例的内部逻辑。工厂类的创建产品类的方法可以被外界直接调用,创建所需的产品对象。
(2)抽象产品(Product):是简单工厂创建的所有对象的父类,负责描述所有实例共有的公共接口。
(3)具体产品(ConcreteProduct):是简单工厂模式的创建目标。

3.优缺点

(1)优点

1)工厂类包含必要的逻辑判断,可以决定在什么时候创建哪一个产品的实例。客户端可以免除直接创建产品对象的职责,很方便的创建出相应的产品。工厂和产品的职责区分明确。
2)客户端无需知道所创建具体产品的类名,只需知道参数即可。
3)也可以引入配置文件,在不修改客户端代码的情况下更换和添加新的具体产品类。

(2)缺点

1)简单工厂模式的工厂类单一,负责所有产品的创建,职责过重,一旦异常,整个系统将受影响。且工厂类代码会非常臃肿,违背高聚合原则。
2)使用简单工厂模式会增加系统中类的个数(引入新的工厂类),增加系统的复杂度和理解难度
3)系统扩展困难,一旦增加新产品不得不修改工厂逻辑,在产品类型较多时,可能造成逻辑过于复杂
4)简单工厂模式使用了 static 工厂方法,造成工厂角色无法形成基于继承的等级结构。
在这里插入图片描述

4.实例

(1)新建java项目test2,在test2的src里新建包factory新建java项目test2,在test2的src里新建包factory在这里插入图片描述
2.在factory新建类Client和FactoryClientDemo
Client

/**
 * @author hz
 * @version 1.0
 */
public class Client {
    //抽象产品
    public interface Product {
        void show();
    }
    //具体产品:ProductA
    static class ConcreteProduct1 implements Product {
        public void show() {
            System.out.println("具体产品1显示...");
        }
    }
    //具体产品:ProductB
    static class ConcreteProduct2 implements Product {
        public void show() {
            System.out.println("具体产品2显示...");
        }
    }
    final class Const {
        static final int PRODUCT_A = 0;
        static final int PRODUCT_B = 1;
        static final int PRODUCT_C = 2;
    }
    static class SimpleFactory {
        public static Product makeProduct(int kind) {
            switch (kind) {
                case Const.PRODUCT_A:
                    return new ConcreteProduct1();
                case Const.PRODUCT_B:
                    return new ConcreteProduct2();
            }
            return null;
        }
    }
}

FactoryClientDemo

package factory;

public class FactoryClientDemo {
    public static void main(String[] args) {
       Client.SimpleFactory simpleFactory = new Client.SimpleFactory();
        Client.Product project1=simpleFactory.makeProduct(0);
        project1.show();
        Client.Product project2;
        project2 = simpleFactory.makeProduct(1);
        project2.show();
    }
}

5.运行结果显示

点击FactoryClientDemo右键运行
在这里插入图片描述

(八)工厂方法模型

1.概念

“工厂方法模式”是对简单工厂模式的进一步抽象化,其好处是可以使系统在不修改原来代码的情况下引进新的产品,即满足开闭原则。

2.工厂方法模式的主要角色

1)抽象工厂(Abstract Factory):提供了创建产品的接口,调用者通过它访问具体工厂的工厂方法 newProduct() 来创建产品。
2)具体工厂(ConcreteFactory):主要是实现抽象工厂中的抽象方法,完成具体产品的创建。
3)抽象产品(Product):定义了产品的规范,描述了产品的主要特性和功能。
4)具体产品(ConcreteProduct):实现了抽象产品角色所定义的接口,由具体工厂来创建,它同具体工厂之间一一对应。
在这里插入图片描述

3.使用场景

用户只需要知道具体工厂的名称就可得到所要的产品,无须知道产品的具体创建过程。
灵活性增强,对于新产品的创建,只需多写一个相应的工厂类。
典型的解耦框架。高层模块只需要知道产品的抽象类,无须关心其他实现类,满足迪米特法则、依赖倒置原则和里氏替换原则。

4.优缺点

(1)优点

用户只需要知道具体工厂的名称就可得到所要的产品,无须知道产品的具体创建过程。
灵活性增强,对于新产品的创建,只需多写一个相应的工厂类。
典型的解耦框架。高层模块只需要知道产品的抽象类,无须关心其他实现类,满足迪米特法则、依赖倒置原则和里氏替换原则。

(2)缺点

类的个数容易过多,增加复杂度
增加了系统的抽象性和理解难度
抽象产品只能生产一种产品,此弊端可使用抽象工厂模式解决。

5.实例

1.新建java项目test3,在test2的src里新建包factory在这里插入图片描述
2.在factory新建类AbstractFactoryTest和ReadXML
AbstractFactoryTest

package factory;

public class AbstractFactoryTest {
    public static void main(String[] args) {
        try {
            Product a;
            AbstractFactory af;
            af = (AbstractFactory) ReadXML.getObject();
            //抽象工厂内容放入到外部配置文件xml/properties等文件中,通过I/O流加载从而创建出抽象工厂
            a = af.newProduct();
            a.show();
        } catch (Exception e) {
            System.out.println(e.getMessage());
        }
    }
}
//抽象产品:提供了产品的接口
interface Product {
    public void show();
}
//具体产品1:实现抽象产品中的抽象方法
class ConcreteProduct1 implements Product {
    public void show() {
        System.out.println("具体产品1显示...");
    }
}
//具体产品2:实现抽象产品中的抽象方法
class ConcreteProduct2 implements Product {
    public void show() {
        System.out.println("具体产品2显示...");
    }
}
//抽象工厂:提供了厂品的生成方法
interface AbstractFactory {
    public Product newProduct();
}
//具体工厂1:实现了厂品的生成方法
class ConcreteFactory1 implements AbstractFactory {
    public Product newProduct() {
        System.out.println("具体工厂1生成-->具体产品1...");
        return new ConcreteProduct1();
    }
}
//具体工厂2:实现了厂品的生成方法
class ConcreteFactory2 implements AbstractFactory {
    public Product newProduct() {
        System.out.println("具体工厂2生成-->具体产品2...");
        return new ConcreteProduct2();
    }
}

ReadXML

package factory;

import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

import java.io.*;
import javax.swing.text.Document;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;

public class ReadXML {
    public static Object getObject() {
        try {
            //创建文档对象
            DocumentBuilderFactory dFactory = DocumentBuilderFactory.newInstance();
            DocumentBuilder builder = dFactory.newDocumentBuilder();
            Document doc;
            doc = (Document) builder.parse(new File("src/FactoryMethod/config1.xml"));
            //获取包含类名的文本节点
            NodeList nl = ((org.w3c.dom.Document) doc).getElementsByTagName("className");
            Node classNode = nl.item(0).getFirstChild();
            String cName = "FactoryMethod." + classNode.getNodeValue();
            //System.out.println("新类名:"+cName);
            //通过类名生成实例对象并将其返回
            Class<?> c = Class.forName(cName);
            Object obj = c.newInstance();
            return obj;
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }
}

6.运行结果显示

点击AbstractFactoryTest右键运行
在这里插入图片描述

(八)抽象工厂模式

1.概述

抽象工厂模式(Abstract Factory Pattern)是围绕一个超级工厂创建其他工厂。该超级工厂又称为其他工厂的工厂。这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。

在抽象工厂模式中,接口是负责创建一个相关对象的工厂,不需要显式指定它们的类。每个生成的工厂都能按照工厂模式提供对象。

2.抽象工厂模式的组成

1)抽象工厂(Abstract Factory):提供了创建产品的接口,它包含多个创建产品的方法 newProduct(),可以创建多个不同等级的产品。
2)具体工厂(Concrete Factory):主要是实现抽象工厂中的多个抽象方法,完成具体产品的创建。
3)抽象产品(Product):定义了产品的规范,描述了产品的主要特性和功能,抽象工厂模式有多个抽象产品。
4)具体产品(ConcreteProduct):实现了抽象产品角色所定义的接口,由具体工厂来创建,它同具体工厂之间是多对一的关系。

在这里插入图片描述

3.实例

/**
 * @author  hz
 * @version 1.0
 */
public class FarmTest {
    public static void main(String[] args) {
        try {
            Farm f;
            Animal a;
            Plant p;
            //读取相应的配置信息,用于生产工厂
            f = (Farm) ReadXML.getObject();
            a = f.newAnimal();
            p = f.newPlant();
            a.show();
            p.show();
        } catch (Exception e) {
            System.out.println(e.getMessage());
        }
    }
}
//抽象产品:动物类
interface Animal {
    public void show();
}
//具体产品:马类
class Horse implements Animal {
    public Horse() {
        System.out.println("具体马类的生成");
    }
    public void show() {
        System.out.println("执行马类的相应操作");
    }
}
//具体产品:牛类
class Cattle implements Animal {

    public Cattle() {
        //具体牛类的生成
        System.out.println("具体牛类的生成");
    }
    public void show() {
        System.out.println("执行马类的相应操作");
    }
}
//抽象产品:植物类
interface Plant {
    public void show();
}
//具体产品:水果类
class Fruitage implements Plant {

    public Fruitage() {
        System.out.println("具体水果类生成");
    }
    public void show() {
        System.out.println("执行水果类的相应操作");
    }
}
//具体产品:蔬菜类
class Vegetables implements Plant {
    public Vegetables() {
        System.out.println("具体蔬菜类生成");
    }
    public void show() {
        System.out.println("执行蔬菜类的相应操作");
    }
}
//抽象工厂:农场类
interface Farm {
    public Animal newAnimal();
    public Plant newPlant();
}
//具体工厂:农场类1
class SGfarm implements Farm {
    public Animal newAnimal() {
        System.out.println("新牛出生!");
        return new Cattle();
    }
    public Plant newPlant() {
        System.out.println("蔬菜长成!");
        return new Vegetables();
    }
}
//具体工厂:农场类2
class SRfarm implements Farm {
    public Animal newAnimal() {
        System.out.println("新马出生!");
        return new Horse();
    }
    public Plant newPlant() {
        System.out.println("水果长成!");
        return new Fruitage();
    }
}

import org.w3c.dom.*;
import javax.xml.parsers.*;
import java.io.File;

/**
 * @author hz
 * @version 1.0
 */
public class ReadXML2 {
    public static Object getObject() {
        try {
            DocumentBuilderFactory dFactory = DocumentBuilderFactory.newInstance();
            DocumentBuilder builder = dFactory.newDocumentBuilder();
            Document doc;
            doc = builder.parse(new File("src/AbstractFactory/config.xml"));
            NodeList nl = doc.getElementsByTagName("className");
            Node classNode = nl.item(0).getFirstChild();
            String cName = "AbstractFactory." + classNode.getNodeValue();
            System.out.println("新类名:" + cName);
            Class<?> c = Class.forName(cName);
            Object obj = c.newInstance();
            return obj;
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }
}

三、总结

通过学习我了解了简单模型和工厂模式的相关概念,工厂模式又分为简单工厂模型、工厂方法模型、抽象工厂模式,了解了这几种模式各自的优缺点,他们相应的使用场景,使用时间等,不仅了解了相关理论方面的知识,应用实践能力也得到提升。

参考资料
菜鸟教程
设计模型系列——抽象工厂模式
设计模型系列——工厂模式

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Java中的单例模式是指一个类只有一个实例,且该类能自行创建这个实例的一种模式。在Java中,单例模式可以通过不同的实现方式来实现,其中一种常见的实现方式是使用静态工厂方法模式(Simple Factory Pattern)。静态工厂方法模式是一种创建型模式,它通过一个静态方法来创建对象,而不是通过直接调用构造方法来创建对象。这种模式可以将对象的创建和使用解耦,提供了一种更加灵活和可控的方式来实现对象的创建。工厂模式Java中常用的设计模式之一,它属于创建型模式,提供了一种创建对象的最佳方式。工厂模式通过定义一个共同的接口或抽象类来创建对象,然后由具体的工厂类来实现这个接口或抽象类,并负责创建具体的对象。这样一来,客户端就可以通过工厂类来创建对象,而无需直接调用对象的构造方法。 [1][2][3<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* *3* [基于java单例模型工厂模式](https://blog.csdn.net/weixin_56102526/article/details/120318486)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v92^chatsearchT0_1"}}] [.reference_item style="max-width: 100%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值