Applying SOLID principles in Flutter (or Dart) helps you write cleaner, scalable, and maintainable code, especially as your app grows. Let’s go through each principle with Flutter-specific examples 👇


🧱 1. S — Single Responsibility Principle (SRP)

A class should have only one reason to change.

❌ Bad:

class UserService {
  void saveUser(User user) {
    // Save to database
  }

  void sendWelcomeEmail(User user) {
    // Send email
  }
}

This class handles both data persistence and email sending — two responsibilities.

✅ Good:

class UserRepository {
  void saveUser(User user) {
    // Save to database
  }
}

class EmailService {
  void sendWelcomeEmail(User user) {
    // Send email
  }
}

Now each class has one clear responsibility, making code easier to test and modify.


🧩 2. O — Open/Closed Principle (OCP)

Classes should be open for extension, but closed for modification.

❌ Bad:

class NotificationService {
  void send(String type, String message) {
    if (type == 'email') {
      // send email
    } else if (type == 'sms') {
      // send sms
    }
  }
}

If you add a new notification type (like push), you must modify this class.

✅ Good (with polymorphism):

abstract class Notifier {
  void send(String message);
}

class EmailNotifier implements Notifier {
  @override
  void send(String message) {
    // send email
  }
}

class SmsNotifier implements Notifier {
  @override
  void send(String message) {
    // send sms
  }
}

class NotificationService {
  final Notifier notifier;

  NotificationService(this.notifier);

  void notify(String message) => notifier.send(message);
}

To add a new type (like PushNotifier), just create a new class — no need to modify existing ones.


⚙️ 3. L — Liskov Substitution Principle (LSP)

Subtypes must be substitutable for their base types.

❌ Bad:

class Bird {
  void fly() {}
}

class Penguin extends Bird {
  @override
  void fly() {
    throw Exception("Penguins can't fly!");
  }
}

Penguin violates LSP because it cannot safely substitute Bird.

✅ Good:

abstract class Bird {}

abstract class FlyingBird extends Bird {
  void fly();
}

class Sparrow extends FlyingBird {
  @override
  void fly() => print("Flying...");
}

class Penguin extends Bird {}

Now both Sparrow and Penguin fit their logical contracts.


🪄 4. I — Interface Segregation Principle (ISP)

Clients should not be forced to depend on methods they do not use.

❌ Bad:

abstract class Worker {
  void work();
  void eat();
}

class Robot implements Worker {
  @override
  void work() => print("Working...");

  @override
  void eat() {
    throw Exception("Robots don't eat!");
  }
}

✅ Good:

abstract class Workable {
  void work();
}

abstract class Eatable {
  void eat();
}

class Human implements Workable, Eatable {
  @override
  void work() => print("Working...");
  @override
  void eat() => print("Eating...");
}

class Robot implements Workable {
  @override
  void work() => print("Working...");
}

🧠 5. D — Dependency Inversion Principle (DIP)

High-level modules should not depend on low-level modules; both should depend on abstractions.

❌ Bad:

class ApiService {
  final HttpClient _client = HttpClient();

  void fetchData() {
    _client.getUrl(Uri.parse("https://api.example.com"));
  }
}

Here, ApiService directly depends on a concrete implementation (HttpClient).

✅ Good:

abstract class HttpService {
  Future<void> get(String url);
}

class HttpClientService implements HttpService {
  @override
  Future<void> get(String url) async {
    // actual request
  }
}

class ApiService {
  final HttpService httpService;

  ApiService(this.httpService);

  void fetchData() {
    httpService.get("https://api.example.com");
  }
}

Now ApiService depends on an abstraction, making it easy to mock or replace in testing.


💡 Applying SOLID in Flutter Apps

Here’s how these principles come together in Flutter:

LayerResponsibilitySOLID in action
UI / WidgetsDisplay data and handle user inputSRP: don’t put logic here
Bloc / ViewModelState managementDIP: depend on abstract services
RepositoryData accessOCP: add new data sources without breaking
ServicesBusiness logic (network, notifications, etc.)SRP + LSP
Models / EntitiesRepresent domain objectsSRP

Using Clean Architecture or DDD (Domain Driven Design) naturally enforces SOLID principles in Flutter.

Categories: Flutter

0 Comments

Leave a Reply

Avatar placeholder

Your email address will not be published. Required fields are marked *