Абстракция. Как мне создать общий статический метод для нескольких типов, которые будут проходить через Dart/Flutter?

Хорошо, я пытаюсь сократить огромное количество стандартного кода для своего приложения. Прямо сейчас я вижу необходимость некоторого рефакторинга и серьезной абстракции.

Я хочу абстрагировать действия CRUD для своего кода базы данных. Сейчас я создаю отдельный файл и дублирую код для каждого объекта. Я чувствую, что должен быть лучший способ, но я не знаю, как сохранить явную безопасность типов при абстрагировании с помощью дженериков.

В настоящее время я делаю что-то подобное для КАЖДОГО объекта:
Я очень уверен, что вы можете видеть, как это может свести кого-то с ума, у меня в приложении более 45 объектов... и многие из них сложнее этого.

abstract class HouseDatabaseAPI {

  /// CREATE EVENT
  /// Create house for authorized user
  static Future<void> createHouse({required House newHouse}) async {
    Box<House> houseBox = await Hive.openBox<House>('house_box');
    await houseBox.put(newHouse);
  }

  /// READ EVENT
  /// Get house for authorized user
  static Future<House?> getHouse() async {
    Box<House> houseBox = await Hive.openBox<House>('house_box');
    House? house = houseBox.getAt(0);
    return house;
  }

  /// UPDATE EVENT
  /// Update house for authorized user
  static Future<void> updateHouse({House? updatedHouse}) async {
    Box<House> houseBox = await Hive.openBox<House>('house_box');
    await houseBox.putAt(0, updatedHouse!);
  }

  /// DELETE EVENT
  /// Delete house from the local machine
  static Future<void> deleteGroup() async {
    Box<House> houseBox = await Hive.openBox<House>('house_box');
    await houseBox.deleteAt(0);
  }
}

Конечно, я хочу, чтобы это было строго типизировано, а НЕ динамично. Что я хотел бы сделать вместо массивного оператора управления потоком (грубый псевдокод):


enum DatabaseAction {
   create,
   read,
   update,
   delete,
}

abstract class DatabaseRoutingAPI {
   
   Future<T> globalDatabaseCreateAction({
      DatabaseAction databaseAction,
      Object object,
      String databaseName,
      }) async {
         Box<T> houseBox = await Hive.openBox<T>(databaseName);
         await houseBox.put(object);
   }      

   ...

}
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
0
39
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Я направлю вас к одному хорошему источнику из моих закладок об обработке данных Hive -> здесь

И здесь я постараюсь ответить на ваш вопрос:

abstract class Database {
  Box get box;
  T get<T>(String id);
  List<T> getAll<T>();
  Future<void> delete(String id);
  Future<void> deleteAll(List<String> keys);
  Future<void> addUpdate<T>(String id, T item);
}

class DatabaseImplementing implements Database {
  const DatabaseImplementing(this._box);
  
  final Box _box;
  
  @override
  Box get box => _box;

  @override
  T get<T>(String id) {
    try {
      final data = box.get(id);
      
      if (data == null) {
        throw Exception('$T not in the box.');
      }
      
      return data;
    } catch (_) {
      rethrow;
    }
  }

  @override
  List<T> getAll<T>() {
    try {
      final data = box.toMap().values;
      
      if (data.isEmpty) {
        throw Exception('$T not in the box.');
      }

      return data.toList().cast<T>();
    } catch (_) {
      rethrow;
    }
  }

  @override
  Future<void> delete(String id) async {
    try {
      await box.delete(id);
    } catch (_) {
      rethrow;
    }
  }

  @override
  Future<void> addUpdate<T>(String id, T item) async {
    try {
      await box.put(id, item);
    } catch (_) {
      rethrow;
    }
  }

  @override
  Future<void> deleteAll(List<String> keys) async {
    try {
      await box.deleteAll(keys);
    } catch (_) {
      rethrow;
    }
  }
}

Конечно, есть много других способов сделать это.

Это именно то, что я искал. На самом деле это не говорит мне о том, как использовать универсальные типы, но это помогает немного ознакомиться. Спасибо. О, и, пожалуйста, разместите здесь какой-нибудь код, чтобы ответить на вопрос более прямо, и я могу принять это как правильный ответ.

RobbB 01.04.2022 08:09

Обновлено. Надеюсь, это поможет вам :)

Arnas 01.04.2022 10:47

Другие вопросы по теме