单例模式,工厂模式

本文介绍了Java中的几种单例模式实现,包括饥饿模式、懒汉式(线程不安全、线程安全及双重检查)、枚举单例和静态内部类单例,分析了它们的优缺点和线程安全性。同时,文章还探讨了简单工厂模式的应用,展示了如何通过工厂模式集中控制对象创建,提高代码灵活性和可维护性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

单例模式

1… 饥饿模式

package singleton;

/**
 * 
 * @author 荞荞 饥饿模式
 */
public class SingletonDemo01 {
//一个私有构造函数
	private SingletonDemo01() {
	};

//生成一个实例
	private static SingletonDemo01 instance = new SingletonDemo01();

//静态方法,获得实例对象
	private static SingletonDemo01 getInstance() {
		return instance;
	}

	public String hello(String name) {
		return "hello" + name;
	}

	/*
	 * 测试多线程下单例模式是否安全
	 * 
	 * @param args
	 */
	public static void main(String[] args) {
		for (int i = 0; i < 100; i++) {
			new Thread(() -> {
				System.out.println(SingletonDemo01.getInstance().hashCode());
			}).start();
		}
	}
}

这种模式简单安全
2… 懒汉式, 有线程问题

package singleton;


/**
 * 单例模式: 懒汉式, 有线程问题
 */
public class SingletonDemo02 {

    private SingletonDemo02(){
        //模拟构造函数的运行耗时
        try {
            Thread.sleep(10);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    private static SingletonDemo02 singletonDemo02 = null;

    public static synchronized SingletonDemo02 getInstance() {

        if (singletonDemo02 == null) {

            singletonDemo02 = new SingletonDemo02();
        }

        return singletonDemo02;
    }

    public String hello(String name) {
        return "hello " + name;
    }

    /*
     * 测试多线程下单例模式是否安全
     * @param args
     */
    public static void main(String[] args) {
        for (int i = 0; i < 100; i++) {
            new Thread(()->{
                System.out.println(SingletonDemo02.getInstance().hashCode());
            }).start();
        }
    }

}

就和上面说的一样,在安全上存在一定的线程问题,并发量一高,容易崩。
3… 懒汉式,线程安全,但性能较低
双重检查

package singleton;
/**
 * 单例模式: 懒汉式,线程安全,但性能较低
 */
public class SingletonDemo03 {

    private SingletonDemo03() {
        //模拟构造函数的运行耗时
        try {
            Thread.sleep(10);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    private static SingletonDemo03 singletonDemo03 = null;

    public static  SingletonDemo03 getInstance(){
        //系统减小同步块来提升性能,可以吗?
        if(singletonDemo03 == null) {
            ///....
            synchronized (SingletonDemo03.class) {
                if(singletonDemo03 == null) {
                    singletonDemo03 = new SingletonDemo03();
                }
            }
        }
        return singletonDemo03;
    }

    public String hello(String name) {
        return "hello " + name;
    }


    /*
     * 测试多线程下单例模式是否安全
     * @param args
     */
    public static void main(String[] args) {
        for (int i = 0; i < 100; i++) {
            new Thread(()->{
                System.out.println(SingletonDemo03.getInstance().hashCode());
            }).start();
        }
    }

}

这种单例模式,重点在于俩次if判断,特别是第二次if判断,因为如果不写这次判断,那么就会出现线程问题,当然是可能,那为什么会出现这问题呢,就是由于CPU只有一个,在极小的时间内,CPU可能去服务其他线程,那这次就会被抢掉,是不是就会出现重新实例对象,不过在经过第一次判断后,通过同步锁,在进行一次判断,就可以实现单例模式,也不会出现线程被抢的问题,就是安全的

4… 懒加载, 线程安全

package singleton;

/**
 * 单例模式: 懒加载, 线程安全
 */
public class SingletonDemo04 {

    //阻止外部实例化
    private SingletonDemo04() {
        //模拟构造函数运行耗时
        try {
            Thread.sleep(10);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    static {

    }

    //使用静态内部类来使用一个SingletonDemo04对象
    private static class SingletonDemoHolder {
        private final static SingletonDemo04 instance = new SingletonDemo04();
    }

    public static SingletonDemo04 getInstance() {
        return SingletonDemoHolder.instance;
    }

    public String hello(String name) {
        return "hello " + name;
    }


    /*
     * 测试多线程下单例模式是否安全
     * @param args
     */
    public static void main(String[] args) {
        for (int i = 0; i < 100; i++) {
            new Thread(()->{
                System.out.println(SingletonDemo04.getInstance().hashCode());
            }).start();
        }
    }
}

package innerclasstest;

import java.util.Random;

public class OuterClass {

    public static long OUTER_DATE = System.currentTimeMillis();
    public static int a = 1;
    static {
        System.out.println("外部类静态块加载时间:" + System.currentTimeMillis());
    }

    public OuterClass() {
        timeElapsed();
        System.out.println("外部类构造函数事件:" + System.currentTimeMillis());
    }

    static class InnerStaticClass {
        static {
            System.out.println("内部类静态块加载时间:" + System.currentTimeMillis());
        }
        // 类加载的初始化阶段是单线程的,类变量的赋值语句在编译生成字节码的时候写在函数中,初始化时单线程调用这个完成类变量的赋值,
        // 所以此处可以保存线程安全的
        public static double INNER_DATE = System.currentTimeMillis();

    }

    class InnerClass {
        public long INNER_DATE = 0;
        public InnerClass() {
            timeElapsed();
            INNER_DATE = System.currentTimeMillis();
        }
    }

    public static void Hello(){System.out.println("Hello");}

    public static void main(String[] args) {
        //System.out.println("外部类常量加载时间:" + OuterClass.OUTER_DATE);
        //OuterClass.Hello();
        //OuterClass outer = new OuterClass();
        //System.out.println("外部类静态变量加载时间:" + OuterClass.OUTER_DATE);
        //System.out.println("外部类静态变量加载时间:" + outer.OUTER_DATE);
        System.out.println(InnerStaticClass.INNER_DATE);

    }

    //单纯的为了耗时而已
    private void timeElapsed() {
        for (int i = 0; i < 10000000; i++) {
            int a = new Random(100).nextInt(), b = new Random(100).nextInt();
            a = a + b;
        }
    }
}

5… enum型

package singleton;

public enum  SingletonDemo05 {

    INSTANCE;

    public String hello(String name) {
        return "hello " + name;
    }

    /*
     * 测试多线程下单例模式是否安全
     * @param args
     */
    public static void main(String[] args) {

        for (int i = 0; i < 100; i++) {
            new Thread(() -> {
                System.out.println(SingletonDemo05.INSTANCE.hashCode());
            }).start();
        }
    }
}

简单工厂

用于产生对象的方法或者式类,称之为工厂。 上面所讲到的单例模式也可以看作为一个特殊的工厂

为了使我们的设计模式变得更加的灵活,我们就通过工厂模式来实现来集中控制对象的创建过程,spring的IOC容器就是工厂模式的经典实现,用于生产指定系列的对象。已鸭子为例,鸭子有真的鸭子,橡皮鸭,电子玩具鸭等。如何能方便的创建出各种鸭子,并将创建过程控制起来,以便于以后的维护和扩展?
工厂

main

package simplefactory;

public class WildDuck extends Duck {

    @Override
    public void quack() {

        System.out.println("我是曾烦鸭。。。。。。。。");

    }

}

DonaldDuck

package simplefactory;

public class DonaldDuck extends Duck {

    @Override
    public void quack() {
    	  System.out.println("我是唐老鸭");
    }

}

rebberduck

package simplefactory;

public class RubberDuck extends Duck {

    @Override
    public void quack() {

    	 System.out.println("我是橡皮鸭,");
    }

}

wildDuck

package simplefactory;

public class WildDuck extends Duck {

    @Override
    public void quack() {

        System.out.println("我是曾烦鸭。。。。。。。。");

    }

}

DuckFactory

package simplefactory;

public class DuckFactory {

    private DuckFactory(){}

    private static DuckFactory duckFactory = new DuckFactory();

    public static final int WILD_DUCK = 1;

    public static final int RUBBER_DUCK = 2;

    public static final int DONALD_DUCK = 3;

    public static final int PJ_DUCK = 4;

    public static Duck getInstance(int duckType) {
        switch (duckType) {
            case WILD_DUCK:
                return new WildDuck();
            case RUBBER_DUCK:
                return new RubberDuck();
            case DONALD_DUCK:
                return new DonaldDuck();
            case PJ_DUCK:
                return new PJDuck();
            default:
                return null;
        }
    }

}

duck

package simplefactory;

public abstract class Duck {

    abstract public void quack();

}

pjduck

package simplefactory;

/**
 * @author L
 * @site www.xiaomage.com
 * @company xxx鍏徃
 * @create聽 2022-06-20 11:12
 */
public class PJDuck extends Duck {
    @Override
    public void quack() {
        System.out.println("我是嘎嘎嘎...");
    }
}

总结:无论是单例模式还是简单工厂模式,在两种设计模式都是想让代码的耦合性降低,在拓展和以后的功能变更和需求增加的时候不至于说去改其他代码,减低bug的出现,使得代码的灵活性得到一个提高。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值