watermelon_mediator 0.0.6 copy "watermelon_mediator: ^0.0.6" to clipboard
watermelon_mediator: ^0.0.6 copied to clipboard

A pure dart package to use the Mediator design pattern in all dart projects, specially flutter mobile apps.

Intro #

This is a 'Make it easy' package that makes your code style easy and more readable and make your code highly clean.

It combines the Mediator design pattern, Single Responsibility principle, and CQRS pattern.

#

For complete explanation and learning of design patterns that used in this package Open this link

Water Melon Mediator Logo

Read First #

Let me explain with an example. You have a multi-layer project. Layer A needs to use some services from layer B. Each service has an implementation logic. So, you are forced to create an instance or use a Dependency Injection to call the instance logic method of Layer B in Layer A.

Example: Layer A

car.getDate();
car.getName(carId);
car.getNameListBy(filter);
.
.
.

Cons: You should import multiple instances for each logic.

With Watermelon Mediator...

First, you separate logic into a single responsibility, one class-one task(In Layer B).

Then, you register it in Meditor to let Meditor know about this task.

In the end, you call the Watermelon Mediator instance _mediator.push(..) in place you need it (In Layer A ), and the Mediator instance handles the rest.

logic implementation? #

If you go above and check the without Meditor example code again, you see most of the time, you have data to pass. Now, let us use this data model class as a key:

final createCarCommand = createCarCommand(name, age);
_mediator.push(createCarCommand)

The Watermelon Mediator has a register method to let the Meditor find the relation between 'createCarCommand' and its implementation.

In summary, you followed those design patterns like this:

1- Meditor for having a central instance manager between layers or the whole app.

2- Command and Query by setting the purpose for your application task. The request in Meditor the same as writing, by naming like this, createCarCommand(), and it is same as reading by naming like this readCarInfoQuery() . A pattern to follow.

3- Single Responsibility for forcing each Request to Meditor(Command or Query / Write or Read) has only one business task to handle.

All three above make your code easy to read, maintain, and expand.

Implementation #

Install #

In the command line:

flutter pub add watermelon_mediator

or in pubspec.yaml:

dependencies: watermelon_mediator: ^0.0.1

Main parts #

The package has four main parts:

1- Meditor Instance

2- Request

3- Request Handler

4- Relate Request to Request Handle

How to make it easy?(Meditor Instance) #

final query = ExampleQuery();
final response = await _mediator.pushAsync(query);  
// Or ExampleCommand, this naming back to you
// about how you want to use Command and 
// Query pattern depends on your business logic

How config it?(Request & Request Handler) #

class AddExampleCommand implements RequestModel<void> {
  AddExampleCommand({required this.data});

  final Data data;
}

The RequestModel model is part of a package that lets the package know that the example class is a 'Request' type(The key for recognizing). Request types are like event parameters that can carry data.

Below part is your task handler and purpose business logic part, which you should write the logic that is related to the purpose; for example, add a car

class AddExampleCommandHandler implements RequestHandler<AddExampleCommand, void> {
  final mockCars = MockUpData();

  @override
  void handle(AddExampleCommand request) {
    // You don't need to write here if you don't
    // need a synchronous method.
    throw UnimplementedError();
  }

  @override
  Future<void> handleAsync(AddExampleCommand request) {
    // You don't need to write here if you don't
    // need an asynchronous method.
    throw UnimplementedError();
  }
}

RequestHandler accepts a generic type, one for RequestModel and another one for ResponseModel. You are free to create a custom ResponseModel to have more clean code. Your handler class offers two 'handle' methods, one for synchronous and one for asynchronous. Logically, if you use one, you should leave the other.

Register(Relate Request to Request Handle) #

@MediatSRequest(requestName: 'AddCarRequest')
class AddExampleCommand...
@MediatSHandler(requestName: 'AddCarRequest')
class AddExampleCommandHandler...

The above annotation @MediatSRequest lets WaterMelon Meditor know we have a request type with this key: "requestName".

We use the same requestName for Handler, too, so Meditor Register request and request handler with exact "requestName".

Remember, "requestName" should be unique in the whole app for each request to Meditor.

At the end, you should add

RequestsRegister();

at the top of the runApp(...); method in your main.dart class, and then run this command

dart run watermelon_mediator -path [WRITE THE SAVE LOCATION OF RequestsRegister() PATH]

Write your path like this: lib/domain/watermelon_mediator

You can remove the -path argument; it generates the RequestsRegister class in the lib directory.

How to use(Example)? #

For example, in your state manager or any part of your architect that you want to call a service or logic,
you can import watermelon_mediator package. By passing the request model to it, it finds the handler automatically and pass the result to it to you.

class CarSateManager {
  final _mediator = Mediator();

  Future<List<Car>> getCarList() async {
    final query = CarListQuery(pageIndex: 0, orderNum: 2);
    final response =
        await _mediator.pushAsync(query);
    return response.cars;
  }

  void addCar(String name) {
    final command = AddCarCommand(car: car);
    _mediator.push(car);
  }
}

Make it easy

0
likes
160
pub points
17%
popularity

Publisher

verified publishergoldcherry.app

A pure dart package to use the Mediator design pattern in all dart projects, specially flutter mobile apps.

Homepage

Documentation

API reference

License

BSD-3-Clause (LICENSE)

More

Packages that depend on watermelon_mediator