# Object-Oriented Programming Concepts in Dart and Flutter

## 1. Abstraction

Abstraction is the process of hiding complex implementation details and showing only the essential features of an object.

### Key Points:
- Abstraction focuses on what an object does rather than how it does it.
- In Dart, abstraction is achieved using abstract classes and interfaces.

### Example:

```dart
// Abstract class
abstract class Shape {
  double calculateArea();
  double calculatePerimeter();
}

// Concrete implementation
class Circle extends Shape {
  double radius;

  Circle(this.radius);

  @override
  double calculateArea() {
    return 3.14 * radius * radius;
  }

  @override
  double calculatePerimeter() {
    return 2 * 3.14 * radius;
  }
}

// Usage
Shape circle = Circle(5);
print(circle.calculateArea()); // Output: 78.5
```

In this example, `Shape` is an abstract class that defines a common interface for all shapes. The `Circle` class provides concrete implementations of the abstract methods.

## 2. Encapsulation

Encapsulation is the bundling of data and the methods that operate on that data within a single unit (class). It restricts direct access to some of an object's components.

### Key Points:
- In Dart, encapsulation is achieved using private variables and methods.
- Private members are denoted by prefixing an underscore (_) to the identifier.

### Example:

```dart
class BankAccount {
  String _accountNumber;
  double _balance;

  BankAccount(this._accountNumber, this._balance);

  double getBalance() {
    return _balance;
  }

  void deposit(double amount) {
    if (amount > 0) {
      _balance += amount;
    }
  }

  bool withdraw(double amount) {
    if (amount > 0 && _balance >= amount) {
      _balance -= amount;
      return true;
    }
    return false;
  }
}

// Usage
var account = BankAccount('123456', 1000);
account.deposit(500);
print(account.getBalance()); // Output: 1500
```

In this example, `_accountNumber` and `_balance` are private variables. They can only be accessed and modified through public methods like `getBalance()`, `deposit()`, and `withdraw()`.

## 3. Inheritance

Inheritance is a mechanism where a new class is derived from an existing class, inheriting its properties and methods.

### Key Points:
- Dart supports single inheritance, where a class can only inherit from one superclass.
- The `extends` keyword is used to create a child class.
- The `super` keyword is used to refer to the parent class.

### Example:

```dart
class Animal {
  void breathe() {
    print('Breathing...');
  }
}

class Mammal extends Animal {
  void walk() {
    print('Walking...');
  }
}

class Dog extends Mammal {
  void bark() {
    print('Woof!');
  }
}

// Usage
var dog = Dog();
dog.breathe(); // Inherited from Animal
dog.walk();    // Inherited from Mammal
dog.bark();    // Dog's own method
```

In this example, `Dog` inherits from `Mammal`, which in turn inherits from `Animal`. This creates a hierarchy where `Dog` has access to all methods from its parent classes.

## 4. Polymorphism

Polymorphism allows objects of different classes to be treated as objects of a common superclass. It enables a single interface to represent different underlying forms (data types).

### Key Points:
- In Dart, polymorphism is achieved through method overriding and interfaces.
- The `@override` annotation is used to indicate that a method is intended to override a superclass method.

### Example:

```dart
abstract class Shape {
  double calculateArea();
}

class Rectangle extends Shape {
  double width;
  double height;

  Rectangle(this.width, this.height);

  @override
  double calculateArea() {
    return width * height;
  }
}

class Circle extends Shape {
  double radius;

  Circle(this.radius);

  @override
  double calculateArea() {
    return 3.14 * radius * radius;
  }
}

// Usage
void printArea(Shape shape) {
  print('Area: ${shape.calculateArea()}');
}

var rectangle = Rectangle(5, 3);
var circle = Circle(2);

printArea(rectangle); // Output: Area: 15.0
printArea(circle);    // Output: Area: 12.56
```

In this example, both `Rectangle` and `Circle` are treated as `Shape` objects. The `printArea()` function demonstrates polymorphism by working with any `Shape` object, regardless of its specific type.

## Conclusion

Understanding these four pillars of object-oriented programming is crucial for effective Dart and Flutter development. They provide a solid foundation for creating modular, maintainable, and scalable applications. Practice implementing these concepts in your projects to reinforce your understanding and improve your coding skills.