Абстракция хранилища данных в J2ME
В процессе написания небольшой програмки для мобильного телефона столкнулся с тем, что работа c файловой системой (JSR-75) поддерживается не на всех телефонах. А данные надо же где-то хранить. Потому я решил реализовать поддержку записи данных как в файловую систему, так и в RecordStore
Но при этом различные объекты пишут данные по разному, поэтому в голову пришла следующая абстракция:
- Все объекты, которые могут быть сохранены, реализуют интерфейс Storable
- Имеется абстрактное хранилище данных, от которого наследуются реализации для файлов и для RecordStore. Это же абстрактное хранилище умеет само выбирать реализацию и выдавать ее по запросу.
Storable
Интерфейс хранимого объекта содержит три метода:- save(DataOutput) - сохранить объект в поток;
- load(DataInput) - загрузить объект из потока;
- clear() - очистить состояние объекта, вызывается в случае, если источник данных отсутствует.
package org.alnomm.storage;
import java.io.DataInput;
import java.io.DataOutput;
/**
* Интерфейс объекта, который может быть сохранен и загружен
*
* @author alno
*/
public interface Storable {
/**
* Сохранить объект в поток
*
* @param os
* поток вывода данных
* @throws Exception
* в случае ошибки
*/
public void save( DataOutput os ) throws Exception;
/**
* Загрузить объект из потока
*
* @param os
* поток ввода данных
* @throws Exception
* в случае ошибки
*/
public void load( DataInput is ) throws Exception;
/**
* Очистить объект
*/
public void clear();
}
Хранилище
Хранилище - объект, отвечающий за сохранение и восстановление хранимых объектов. Для возможности доступа из произвольной точки программы, хранилище реализует паттерн синглтон. Также, хранилище исполняет обязанности по выбору необходимой реализации, т.е. работает как абстрактная фабрика. Несколько слов о выборе реализации:- Для того, чтобы класс ненужной реализации не загружался вообще, загрузка реализации происходит по имени класса, через механизм Reflection.
- Для проверки поддержки JSR-75 производится попытка загрузки класса FileConnection, и если она успешна, то используется реализация на основе файловой системы, иначе на основе RecordStore.
package org.alnomm.storage;
public abstract class Storage {
private static Storage instance = null;
/**
* Получить экземпляр хранилища
*
* @return экземпляр хранилища
* @throws Exception
* если произошла ошибка
*/
public static Storage instance() throws Exception {
if ( instance == null ) {
String className = "org.alnomm.storage.RecordStorage"; // По умолчанию храним данные в RecordStore
if ( hasFilesystem() ) // Если есть файловая система, то загружаем другое хранилище
className = "org.alnomm.storage.FileStorage";
instance = (Storage) Class.forName( className ).newInstance();
}
return instance;
}
/**
* Сохранить объект
*
* @param obj
* объект
* @throws Exception
* если произошла ошибка
*/
public abstract void save( Storable obj ) throws Exception;
/**
* Сохранить объект
*
* @param obj
* объект
* @throws Exception
* если произошла ошибка
*/
public abstract void load( Storable obj ) throws Exception;
/**
* Проверить, поддерживает ли телефон операции с ФС
*
* @return
*/
private static boolean hasFilesystem() {
try {
Class.forName( "javax.microedition.io.file.FileConnection" ); // Проверяем, можем ли загругить класс
return true;
} catch ( Exception e ) {
return false;
}
}
}
