Первое и, безусловно, самое важное решение, которое вы должны принять, - хотите ли вы получить доступ к этой базе данных синхронно или асинхронно. У них обоих есть свои плюсы и минусы, поэтому это будет зависеть от вашей ситуации.
Синхронный
- более простая архитектура
- легче читать
- лучше подходит для небольших операций
- замораживает приложение при выполнении операций
Хорошо для небольших приложений
Асинхронный
- более сложная архитектура
- труднее читать
- длительные операции не замораживают пользовательский интерфейс
- если вам нужно синхронизировать с серверной БД, вы можете создать интерфейс для локальных и удаленных служб БД (например, класс
LocalUserService
и RemoteUserService
оба реализуют интерфейс, который заставляет их иметь метод saveUser()
)
Подходит для более масштабных приложений и синхронизации локальных и удаленных данных.
Я склонен почти всегда выбирать асинхронный подход - поскольку он более гибкий - и абстрагироваться от сложности в ... классе-оболочке. Так что это отвечает на ту часть вашего вопроса.
Архитектура
Мне не нравятся фреймворки, поэтому я не могу ответить на ваш вопрос о Mate
или -shudder- Cairngorm
. Но вот что я считаю довольно хорошим подходом:
- для каждой сущности в вашей модели создайте объект доступа к данным (DAO), который будет возвращать только необработанные результаты запроса (например,
UserDAO
для запроса пользователей). Этот класс должен содержать только запросы.
- в соответствии с каждым DAO создайте Builder / Factory, который может принимать эти результаты запроса и объекты модели появления (например, UserBuilder)
- Обычно этого достаточно для меня, но вы также можете объединить их в сервисный уровень (например, UserService). Этот уровень обслуживания также может помочь сопоставить существующий уровень удаленного обслуживания с вашими локальными службами.
Что касается сохранения соединения открытым. Я всегда так делал и у меня никогда не было с этим проблем. Я точно не знаю, что происходит, когда происходит сбой приложения и соединение не было должным образом закрыто, но речь идет не о Oracle или SQL Server. Я не думаю, что SQLite будет держать открытые указатели или что-то в этом роде, так как это простой файл, но я могу ошибаться.
Редактировать: некоторые дополнительные сведения о шаблоне DAO / Factory (согласно запросу OP).
Пример UserDAO с одной функцией:
public class PupilDAO extends AsynchronousDAO {
public function getUserById(id:int, handleResult:Function):Responder {
return getResults(
"SELECT * FROM user WHERE user_id = ?",
handleResult, [id]
);
}
}
Как видите, я абстрагировал сложность от базового класса AsynchronousDAO
, поэтому мы можем видеть только необходимую информацию в UserDAO. Функция handleResult
- это обратный вызов, который будет вызываться всякий раз, когда запрос готов, передавая набор результатов в качестве аргумента. Обычно мы передаем этот набор результатов в класс factory / builder.
Пример UserBuilder:
public class UserBuilder {
public function buildUser(record:*):User {
var user:User = new User();
user.id = record.user_id;
user.firstname = record.firstname;
user.lastname = record.lastname;
return user;
}
}
Это, очевидно, простой пример, но вы можете создавать более сложные структуры данных в компоновщике. Для получения информации о разнице между шаблонами Factory и Builder я рекомендую Google.
Теперь давайте свяжем это вместе в классе обслуживания:
public class UserService {
private var dao:UsetDAO;
private var builder:UserBuilder;
public UserService(dao:UserDAO, builder:UserBuilder) {
this.dao = dao;
this.builder = builder;
}
public function getUserById(id:int, handleResult):void {
var handleResultSet:Function = function(resultSet:SQLResult):void {
var user:User = builder.buildUser(resultSet.data[0]);
if (handleResult!= null) handleResult(user);
}
dao.getUserById(id, handleResultSet);
}
}
Наконец, давайте используем трио:
var userService = new UserService(new UserDAO(), new UserBuilder());
userService.getUserById(1, handleUser);
function handleUser(user:User):void {
trace(user);
}
Для примера я сконструировал классы с помощью new
и передал дао и конструктор в качестве аргументов конструктора, но вы можете использовать инъекцию или синглтоны или любой другой фреймворк, который вам нравится делать для вас.