• Design Pattern: Registry of Singleton 模式


    一句话概括:您可以使用父类别来统一管理多个继承的子类别之Singleton实例,您可以在需要的时候再向父类别注册子类 Singleton,必要时随时调整传回的子类别Singleton。

    考虑使用 Singleton 模式 时拥有子类别的问题,在Singleton模式中的getInstance()通常是一个静态方法,不能在子类别中重新定义它,关于子类别实例的产生交由getInstance()来进行是最好的选择,例如:

    public class Singleton {
        private static Singleton instance = null;
        private Singleton() {
            // ....
        }
    
        public static Singleton getInstance() {
            if (instance == null) {
                // getEnv表示系统环境变数
                String style = getEnv("style"); 
    
                if (style.equals("child1"))
                    instance = new ChildSingleton1();
                else if (style.equals("child2r"))
                    instance = new ChildSingleton2();
                else
                    instance = new Singleton();
            }
    
            return _instance;
        }
    
        // ....
    }

    上面这个程式片段改写自 Gof 书中关于Singleton的例子,并用Java实现;在书中指出,这个例子的缺点是每增加一个子类别,getInstance()就必须重新修改,这个问题在Java中可以使用Reflection机制来解决:

    public class Singleton {
        private static Singleton instance = null;
        private Singleton() {
            // ....
        }
    
        public static Singleton getInstance() {
            if (instance == null) {
                // getEnv表示环境变数
                String style = getEnv("style");
    
                try {
                    instance = (Singleton)
                              Class.forName(style).newInstance();
                }
                catch(Exception e) {
                    System.out.println(
                       "Sorry! No such class defined!");
                }
            }
    
            return instance;
        }
    
        // ....
    }

    上面的方式使用了Java的Reflection机制,并透过环境变数设定要产生的子类Singleton,如果不使用Reflection的话,Gof 书中提出的改进方法是使用Registry of Singleton方法:

    import java.util.*;
    
    public class Singleton {
        // 注册表,用于注册子类别物件
        private static Map registry = new HashMap(); 
        private static Singleton instance;
    
        public static void register(
                     String name, Singleton singleton) {
            registry.put(name, singleton);
        }
    
        public static Singleton getInstance() {
            if (instance == null) {
                // getEnv表示取得环境变数
                String style = getEnv("style");
                instance = lookup(style);
            }
    
            return instance;
        }
    
        protected static Singleton lookup(String name) {
            return (Singleton) registry.get(name);
        }
    }
    

    在Gof书中使用List来实现注册表,而在这边使用HasMap类别来实现,它是由Java SE所提供的;在父类别中提供一个register() 以注册Singleton的子类别所产生之实例,而注册的时机可以放在子类别的建构方法中加以实现,例如:

    public class ChildSingleton1 extends Singleton {
        public ChildSingleton1() {
            // ....
            // 注册子类别物件
            register(getClass().getName(), this);  
        }
    }

    若要利用Singleton,则先使用这个子类别产生物件,这会向父类别注册物件,之后透过Singleton父类别来取得物件:

    // 必须先启始这段注册程序
    // 产生并注册ChildSingleton1物件
    new ChildSingleton1();
    // 产生并注册ChildSingleton2物件
    new ChildSingleton2();

    // 注册完成,可以使用父类别来取得子类的Singleton
    // 至于取回何哪一个,视您的环境变数设置决定
    Singleton childSingleton = Singleton.getInstance();

    这种方式的缺点是您必须在程式中启始一段程序,先向父类别注册子类的Singleton,之后才能透过父类别来取得指定的子类别Singleton实例, 好处是可以适用于没有Reflection机制的语言,如果您想要改变Singleton父类传回的子类Singleton,可以在上面的 Singleton类别中加入一个reset()方法,将instance设定为null,然后重新设定环境变数,之后再利用 Singleton父类的getInstance()方法重新取得注册表中的其它子类。
    事实上Registry of Singleton的真正优点正在于此,您可以使用父类别来统一管理多个继承的子类别之Singleton实例,您可以在需要的时候再向父类别注册子类 Singleton,必要时随时调整传回的子类别Singleton。

  • 相关阅读:
    无法设置 / 添加网络打印机?报错 无法保持设置?
    tp剩余未验证内容-5
    再谈 iptables 防火墙的 指令配置
    tp剩余未验证内容-4
    tp剩余未验证内容-3
    CentOS7.4安装配置mysql8 TAR免安装版
    CentOS7中systemctl的使用与CentOS6中service的区别
    CentOS下如何查看并杀死僵尸进程
    CentOS SVN服务器管理多项目
    swoole+Redis实现实时数据推送
  • 原文地址:https://www.cnblogs.com/rollenholt/p/2467014.html
Copyright © 2020-2023  润新知