November 7, 2025
Flutter

how to use solid principles in flutter

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.

Related posts

How to setup Flutter with VSCode Step By Step Guide

Dheeraj Pal

How to make Diary App using Flutter and Getx

Dheeraj Pal

What is difference between const and final keyword in flutter

Dheeraj Pal

Leave a Comment