zoukankan      html  css  js  c++  java
  • Java设计模式之单例模式

    场景问题

    业内都有一个不朽的传说。就是程序猿是找不到女朋友的。没有女朋友怎么行。

    今天咱就带着大家用Java的知识。来”追”一个女朋友。
    那在追女友之间阿,咱先定一个女友的标准。

    只是。这个标准不能乱定是吧。不能像网上流传的一样。”女的,活的”。做为一个有理想的程序猿。我认为我的女朋友,要有身高吧,然后罩杯也不正确低,低重也不好太胖阿。

    那么用 Java 语言来表述,就是这个”女友”得有三个属性。身高。体重,与胸围。所以。咱就建这么个类。叫 GirlFriend.

    public class GirlFriend {
        private String cup;
        private int height;
        private int weight;
    
        public String getcup() {
            return cup;
        }
    
        public void setcup(String cup) {
            this.cup = cup;
        }
    
        public int getHeight() {
            return height;
        }
    
        public void setHeight(int height) {
            this.height = height;
        }
    
        public int getWeight() {
            return weight;
        }
    
        public void setWeight(int weight) {
            this.weight = weight;
        }
    }

    那如今已经准备了一个女友类。

    接下来,是不是就要产生一个女朋友了。

    那咱们就在client new一个呗。

    public class Client {
        public static void main(String[] args) {
            GirlFriend gf = new GirlFriend();
        }
    }

    问题
    大家试想一下。假设我们在client里,再去”找”一个女友,是不是也是能够的。

    public class Client {
        public static void main(String[] args) {
            GirlFriend gf = new GirlFriend();
            GirlFriend gf1 = new GirlFriend();
            System.out.println(gf==gf1);
        }
    }

    并且。上述的代码。终于的结果也是 false。
    那,做为一个有原则的男人,是不是要限制这样的情况发现呢。

    单例模式

    单例模式定义

    解决上面问题的一种方式,就是用单例模式。

    那么,何谓单例模式?我们先来看一下定义:

    保证一个类仅有一个实例,并提供一个它的全局訪问点。

    实现方法

    在 Java 中。单例模式实现分为两种。一种称为懒汉式,一种又称为饿汉式。

    我们分别来看一下这两种方式是怎么实现的。


    1:懒汉式

    public class GirlFriend {
        private String cup;
        private int height;
        private int weight;
        //定义一个变更来储存实例
        private static GirlFriend  instance =null;
        private GirlFriend(){
    
        }
        public static GirlFriend getInstance(){
            //推断实例是否为空
            if(null==instance){
                //假设当前实例还没有创建,那就生成一个,并赋值给储存实例
                instance = new GirlFriend();
            }
            return instance;
        }
        //下面都是演示样例方法
    
        public String getcup() {
            return cup;
        }
    
        public void setcup(String cup) {
            this.cup = cup;
        }
    
        public int getHeight() {
            return height;
        }
    
        public void setHeight(int height) {
            this.height = height;
        }
    
        public int getWeight() {
            return weight;
        }
    
        public void setWeight(int weight) {
            this.weight = weight;
        }
    }

    2:饿汉式:

    public class GirlFriend {
        private String cup;
        private int height;
        private int weight;
        //定义一个变更来储存创建好的实例
        private static GirlFriend  instance =new GirlFriend();
        private GirlFriend(){
    
        }
        public static  GirlFriend getInstance(){
    
            return instance;
        }
        //下面都是演示样例方法
    
        public String getcup() {
            return cup;
        }
    
        public void setcup(String cup) {
            this.cup = cup;
        }
    
        public int getHeight() {
            return height;
        }
    
        public void setHeight(int height) {
            this.height = height;
        }
    
        public int getWeight() {
            return weight;
        }
    
        public void setWeight(int weight) {
            this.weight = weight;
        }
    }

    3:client调用
    那这个时候,我们再调用。得到的就是一个唯一的女友了。

    public class Client {
        public static void main(String[] args) {
            GirlFriend gf = GirlFriend.getInstance();
            GirlFriend gf1 =GirlFriend.getInstance();
            System.out.println(gf==gf1);
        }
    }

    因为我们在女友类里,把构造方法给私有化了,所以。在客端端调用的时候。得到的就是唯一的一个女友对象了。

    (在这里,我们临时不考虑反射。)
    4:关于命名
    事实上,所谓饿汉与懒汉也是一种比較形象的说法吧。


    所谓饿汉。也就是说你比較饥渴,饿,于是就在装载类的时候就已经创建好”女友了”。那懒汉。也就是懒。等你须要女友的时候再去创建。

    延迟载入与缓存

    延迟载入

    懒汉式的单例模式体现了延迟载入的思想。那什么是延迟载入。
    简单一点来主,延迟载入就是一開始不去载入数据或者资源,等到要用到的时候,才去载入,也就是 Lazy Load。

    这在实际开发中也是一种常见的思想,尽可能的节约资源。

    缓存

    懒汉式还体现了缓存的思想,缓存在开发中也是常见的功能。
    简单的来说,就是当某些资源须要被重复使用的时候,而这些资源储存在系统外部。比方数据库,硬盘等。那假设每次操作都要又一次读取一次。显然非常浪费资源。所以,懒汉式载入中,在一開始,就定义了一个变量。来储存要生成的实例。也就是:

    private static GirlFriend  instance =null;

    之后,再生成实例后,赋值给变量。

    线程安全

    从线程安全性上来讲。不加同步的懒汉式是线程不安全的。

    也就是说。假设多个线程同一时候调用getInstance方法,就会导制并发问题。那该怎样解决。

    事实上仅仅要加上 synchronized就能够了。也就是:

      public static synchronized GirlFriend getInstance(){}

    可是这样一来,就会降低訪问速度。并且每次都要推断。那该怎样实现,这里就要用到双重加锁。


    所谓双重加锁。指的是。不是每一次 getInstance都要同步。

    而是先不同步,进入方法之后,先检查实例是否存在。

    假设不存在。再进入同步块,这是第一重检查。进入同步块之后。再次检查实例是否存在,假设不存在。就在同步情况下创建一个实例。这是第二重检查。这样一来,就能够降低多次在同步情况下进行推断所浪费的时间了。
    实现代码例如以下:

      private volatile static GirlFriend  instance =null;
        public static  GirlFriend getInstance(){
            if(null==instance){
                synchronized (GirlFriend.class){
                    if(instance==null){
                        instance = new GirlFriend();
                    }
                }
            }
            return instance;
        }

    注:双重载入须要在 java5以上的版本号。

    枚举

    事实上,另一种更高效的单例实现。也就是单元素的枚举。关于枚举的介绍,我这里就不多做介绍了。

    我们看一下怎样用枚举实现单例。

    public enum  GirlFriend {
        instance;
        private String cup;
        private int height;
        private int weight;
        //下面都是演示样例方法
    
        public String getcup() {
            return cup;
        }
    
        public void setcup(String cup) {
            this.cup = cup;
        }
    
        public int getHeight() {
            return height;
        }
    
        public void setHeight(int height) {
            this.height = height;
        }
    
        public int getWeight() {
            return weight;
        }
    
        public void setWeight(int weight) {
            this.weight = weight;
        }
    }

    使用枚举实现单例会使代码更加的简洁。并且。从 JVM 上绝对的防止了多次实例化。

  • 相关阅读:
    读入输出优化模板
    HDU-2647 Reward(拓扑排序)
    HDU-2647 Reward(拓扑排序)
    HDU-2647 Reward(拓扑排序)
    HDU-2647 Reward(拓扑排序)
    Using KafkaBolt to write to a kafka topic
    Using KafkaBolt to write to a kafka topic
    Using KafkaBolt to write to a kafka topic
    Using KafkaBolt to write to a kafka topic
    getElementById() 获取指定ID的第一个元素
  • 原文地址:https://www.cnblogs.com/llguanli/p/8438099.html
Copyright © 2011-2022 走看看