实现Singleton模式以访问任何地方的对象

时间:2016-05-23 17:24:17

标签: java android singleton

目前,我有一个类,其构造函数采用用户名,密码和上下文。我希望能够从任何地方访问这个对象,所以我想实现一个单例模式。

当前构造函数使用传入的凭据来验证通过该类的未来api调用。如果我要实现单例模式,我的第一个想法就是让getInstace()方法获取用户名,密码等等。但是每次我抓住一个实例时都必须传递该信息似乎是错误的。因此,我在考虑在抓取第一个实例时添加某种.authenticate(usr, pswrd)方法。

我的问题是,这是正确的做法吗?如果没有,那么处理这个问题的好方法是什么?下面是当前的代码:

构造

public Play(String username, String password, Context context) {
        api = getApi(username, password);
        Intent intent = new Intent(context, MyService.class);
        context.bindService(intent, mConnection, Context.BIND_AUTO_CREATE);

        //check if first run
        //if so, call api for info and store locally
        //if not, update as needed

        SharedPreferences pref = context.getSharedPreferences("pref", Context.MODE_PRIVATE);
        SharedPreferences.Editor editor = pref.edit();

        if (pref.getBoolean("first_run", true)) {
            loadInitialData(context);
        }

        editor.putBoolean("first_run", false);
        editor.commit();
    }

1 个答案:

答案 0 :(得分:1)

Singleton模式限制了类的实例化,并确保java虚拟机中只存在该类的一个实例。单例类必须提供一个全局访问点来获取类的实例。单例模式用于日志记录,驱动程序对象,缓存和线程池

此代码未经过测试,但应该让您了解在使用singleton pattern时如何使用SharedPrefrencess

构造函数是私有的,因此只有getInstance()方法才能访问该实例,因此如果该类不存在或者之前实例化,则会创建该类的实例

需要

同步以确保多个线程第一次尝试创建实例时

import android.content.Context;
import android.content.SharedPreferences;

/**
 * Created by Pankaj Nimgade on 23-05-2016.
 */
public class Play {

    /**
     * volatile keyword ensures that multiple threads handle the uniqueInstance
     * variable correctly when it is being initialized to Singleton instance
     */
    private volatile static Play play;

    private static final String XML_FILE = "play_xml_file.xml";
    private static final String KEY_DATA = "SOME_DATA_KEY";
    private static final String KEY_USERNAME = "SOME_USERNAME_KEY";
    private static final String KEY_PASSWORD = "SOME_PASSWORD_KEY";

    private static SharedPreferences sharedPreferences;

    private static SharedPreferences.Editor editor;

    private Play() {
    }

    public static Play getInstance(Context context) {
        if (play == null) {
            synchronized (Play.class) {
                if (play == null) {
                    sharedPreferences = context.getSharedPreferences(XML_FILE, Context.MODE_PRIVATE);
                    editor = sharedPreferences.edit();
                    play = new Play();
                }
            }
        }
        return play;
    }

    public boolean saveSomeData(String someData) {
        editor.putString(KEY_DATA, someData);
        return editor.commit();
    }

    public String readSomeData() {
        return sharedPreferences.getString(KEY_DATA, "default Value");
    }

    public boolean saveUserNameData(String username) {
        editor.putString(KEY_USERNAME, username);
        return editor.commit();
    }

    public String readUserNameData() {
        return sharedPreferences.getString(KEY_USERNAME, "default username Value");
    }

    public boolean savePasswordData(String password) {
        editor.putString(KEY_PASSWORD, password);
        return editor.commit();
    }

    public String readPasswordData() {
        return sharedPreferences.getString(KEY_PASSWORD, "default password value");
    }
}

在上面的方法中我正在创建类lazy的实例,因为实例只会在需要时创建,尽管代码是线程安全的并且可以在所有Java版本上工作,你可能想要考虑不同的方法来实现这个如果您使用的是Java 5及更高版本。

https://sourcemaking.com/design_patterns/singleton/java/1

public class Singleton {
  // Private constructor prevents instantiation from other classes
  private Singleton() {}

  /**
   * SingletonHolder is loaded on the first execution of Singleton.getInstance() 
   * or the first access to SingletonHolder.INSTANCE, not before.
   */
  private static class SingletonHolder { 
    private static final Singleton INSTANCE = new Singleton();
  }

  public static Singleton getInstance() {
    return SingletonHolder.INSTANCE;
  }
}

与调用getInstance()的时刻相比,内部类不会被引用(因此不会由类加载器加载)。因此,该解决方案是线程安全的,无需特殊的语言结构(即易失性或同步)。