Страницы

24 мая 2012 г.

Паттерн Singleton (Одиночка)

Сегодня начнем тематику паттернов проектирования. Паттерны проектирования - это описание некоторых проблем, возникающих во время объектно-ориентированного проектирования, а также способов их решения (как практических, так и теоретических). Говоря иначе - это примеры правильных подходов к решению классических задач проектирования.
Хотелось бы начать с самого распространенного паттерна - Singleton (Одиночка).

Задача: Ограничить количество экземпляров некоторого класса. 
Реализация:
- Ленивый / Lazy initialization
public class Singleton {
        private static Singleton instance = null;
 
        private Singleton() {   }
 
        public static synchronized Singleton getInstance() {
                if (instance == null) {
                        instance = new Singleton();
                }
                return instance;
        }
}

- Активный / Eager initialization
Если программа будет всегда нужна, например, или если стоимость создания экземпляра не слишком велика по времени и ресурсам, программист может переключиться на активную инициализацию, которая всегда создает экземпляр:
public class Singleton {
    private static Singleton _instance = new Singleton();
 
    private Singleton() {}
 
    public static Singleton getInstance() {
        return _instance;
    }
}

Далее разберем нашу композицию по ноткам:
Конструктор класса необходимо объявить с модификатором видимости private. Это предотвратит создание экземпляров класса как с помощью класса Singleton, так и с помощью его наследников. В связи с этим к объявлению класса смело можно дописать модификатор final.

Метод getInstance() создаст ровно один экземпляр класса Singleton. Этот метод объявлен как synchronized. Сделано это вот почему. В многопоточных программах при одновременном вызове метода getInstance() из нескольких потоков можно создать несколько экземпляров класса Singleton. А должен остаться только один!

От модификатора synchronized можно избавиться. Для этого _instance нужно проинициализировать:
private static final Singleton _instance = new Singleton(),
а в методе getInstance() удалить "if".
Но использование ленивой(поздней)инициализации (lazy initialization) предпочтительнее в случае, если создание экземпляра класса занимает много времени.

А теперь перейдем к применению, зачем нужен Singleton:
Мне приходится чаще всего использовать этот паттерн при работе с конфигурацией. Иногда конфигурацию программы удобно хранить в файле. Допустим, это будет простой текстовый файл “props.txt” со строками типа “ключ=значение”. Нам нужно гарантировать, что конфигурация в программе будет в единственном экземпляре. Вторую мы бы и так не создали, но нужно запретить это делать пользователю класса. Итак,

import java.util.*;
import java.io.*;

public class Configuration {
    private static Configuration _instance = null;

    private Properties props = null;

    private Configuration() {
         props = new Properties();
     try {
     FileInputStream fis = new FileInputStream(
                    new File(“props.txt”));
     props.load(fis);
     }
     catch (Exception e) {
         // обработайте ошибку чтения конфигурации
     }
    }

    public synchronized static Configuration getInstance() {
        if (_instance == null)
            _instance = new Configuration();
        return _instance;
    }

    // получить значение свойства по имени
    public synchronized String getProperty(String key) {
        String value = null;
        if (props.containsKey(key))
            value = (String) props.get(key);
        else {
            // сообщите о том, что свойство не найдено
        }
        return value;
    }
}

Теперь для работы с конфигурацией можно использовать конструкцию вида:
String propValue = Configuration.getInstance()
    .getProperty(propKey);

Если имена свойств в “props.txt” меняться не будут, можно описать их в классе таким образом:
public static final String PROP_KEY = “propKey”,

а значения получать так:
String propValue = Configuration.getInstance().
getProperty(Configuration.PROP_KEY).
Так же Singleton частенько применяется для коннекта к базам данных...
На том пока все :)

Комментариев нет:

Отправить комментарий