Dustin Silk
Dustin Silk

Reputation: 4620

Dart: Access class sibling mixin variables

I have a very large class called DatabaseService that fetches, caches, and updates various streams of data. I'm now attempting to separate each logical block of data into individual files to make it easier to manage. However, I'd like to keep all the methods and streams accessible by providing just the one DatabaseService file.

My DatabaseService has these various groups of methods and streams of data that I'm separating into individual files:

The difficulty is that each group of data depends on streams from the other groups of data. For example, comments require the stories feed, and so on: Comments < stories < feed < user

My first iteration looked like this:

class DatabaseService {
  // Here, i expose the various streams from each subclass
  Stream<User> userStream = UserService.instance.userStream;
  Stream<Feed> feedStream = FeedService.instance.feedStream;
  Stream<Stories> storiesStream = StoriesService.instance.storiesStream;
  Stream<Comments> commentsStream = CommentsService.instance.commentsStream;
  ...

  DatabaseService() {
  }

Things quickly become messy when I have to push data to each sub-service and expose multiple methods, or if i need to access methods from one another.

I've looked into using mixins, which look great, but I can't access streams from one sub-class to another.

Is there a better way to do this?

Upvotes: 2

Views: 954

Answers (1)

Dustin Silk
Dustin Silk

Reputation: 4620

The trick is to make a Base abstract Class which lays out the blueprints for the class. Then have each of the subclasses implement the base class so that they are aware of each other property of the class across each one. Finally the DatabaseService implements the base class and uses each of the subclasses as mixins.

See below for an example:

BaseDatabase:


abstract class BaseDatabase {
  final firestore = FirestoreService.instance;
  final functions = FunctionsService.instance;

  ValueStream<User> userStream;
  Future<void> setUser(User user);

  Stream<Feed> feedStream;
  Stream<Story> storiesStream;
  Stream<List<Comment>> commentsStream;
  Stream<Location> locationStream(String locationId);
}

DatabaseService:

part 'parts/feed.dart';

class DatabaseService extends BaseDatabase
    with
        UserService,
        LocationService,
        FeedService,
        CommentsService,
        ... {

  DatabaseService({authService}) {
    // Any other required initialization code here, for example something like this.
    authService.uid().listen((uid) => userId.add(uid));
  }
}

FeedService:

part of '../database_service.dart';

mixin FeedService implements BaseDatabase {
  ValueStream<Feed> get feedStream => _getFeedStream().shareValue();

  Stream<Feed> _getFeedStream() => 
    // userStream is from the UserService.. Winning!
    userStream
      .distinct((oldUser, newUser) => oldUser.id == newUser.id)
      .switchMap((user) => firestore.get(...)
        .where((feeds) => feeds.length > 0)
        .map((feeds) => feeds[0]));

Upvotes: 1

Related Questions