# Days 7-8: Advanced OOP

#### Objective:

* Learn inheritance, polymorphism, abstraction, and encapsulation.
    
* Practice by creating small projects based on OOP concepts.
    

---

### 1\. Inheritance

Inheritance allows a class to inherit properties and methods from another class.

```dart
// Parent class
class Animal {
  String name;

  Animal(this.name);

  void eat() {
    print('$name is eating');
  }
}

// Child class
class Dog extends Animal {
  Dog(String name) : super(name);

  void bark() {
    print('$name is barking');
  }
}

void main() {
  Dog dog = Dog('Buddy');
  dog.eat();  // Inherited method
  dog.bark(); // Child class method
}
```

**Explanation:**

* `Animal` is the parent class with a property `name` and a method `eat`.
    
* `Dog` is the child class that extends `Animal` and inherits its properties and methods.
    
* The `Dog` class also has its own method `bark`.
    

**Diagram:**

* **Figure 1:** Inheritance in Dart.
    
    ![](https://cdn.hashnode.com/res/hashnode/image/upload/v1716607356470/b1666d99-63ea-4ebc-8610-e83ea9d829f9.png align="center")
    

---

### 2\. Polymorphism

Polymorphism allows objects to be treated as instances of their parent class rather than their actual class.

```dart
class Animal {
  void sound() {
    print('Animal makes a sound');
  }
}

class Dog extends Animal {
  @override
  void sound() {
    print('Dog barks');
  }
}

class Cat extends Animal {
  @override
  void sound() {
    print('Cat meows');
  }
}

void main() {
  Animal myDog = Dog();
  Animal myCat = Cat();

  myDog.sound(); // Dog barks
  myCat.sound(); // Cat meows
}
```

**Explanation:**

* The `Animal` class has a method `sound`.
    
* The `Dog` and `Cat` classes override the `sound` method.
    
* Polymorphism allows calling the `sound` method on `Animal` references, which results in calling the overridden methods in `Dog` and `Cat`.
    

**Diagram:**

* **Figure 2:** Polymorphism in Dart.
    
    ![](https://cdn.hashnode.com/res/hashnode/image/upload/v1716607732685/8747e379-382f-42f0-921f-47ccc3564eaf.png align="center")
    

---

### 3\. Abstraction

Abstraction allows defining methods without implementing them, using abstract classes and methods.

```dart
abstract class Shape {
  void draw(); // Abstract method
}

class Circle extends Shape {
  @override
  void draw() {
    print('Drawing a circle');
  }
}

class Rectangle extends Shape {
  @override
  void draw() {
    print('Drawing a rectangle');
  }
}

void main() {
  Shape circle = Circle();
  Shape rectangle = Rectangle();

  circle.draw(); // Drawing a circle
  rectangle.draw(); // Drawing a rectangle
}
```

**Explanation:**

* `Shape` is an abstract class with an abstract method `draw`.
    
* `Circle` and `Rectangle` classes extend `Shape` and implement the `draw` method.
    
* Abstract classes cannot be instantiated, but they can be used as reference types.
    

**Diagram:**

* **Figure 3:** Abstraction in Dart.
    
    ![Abstraction Diagram](https://i.imgur.com/Ntxr4wN.png align="left")
    

---

### 4\. Encapsulation

Encapsulation restricts access to certain properties and methods using access modifiers.

```dart
class BankAccount {
  String _accountNumber; // Private property
  double _balance;       // Private property

  BankAccount(this._accountNumber, this._balance);

  // Getter for account number
  String get accountNumber => _accountNumber;

  // Getter for balance
  double get balance => _balance;

  // Method to deposit money
  void deposit(double amount) {
    if (amount > 0) {
      _balance += amount;
    }
  }

  // Method to withdraw money
  void withdraw(double amount) {
    if (amount > 0 && amount <= _balance) {
      _balance -= amount;
    }
  }
}

void main() {
  BankAccount account = BankAccount('123456', 1000.0);

  account.deposit(500.0);
  print('Balance: ${account.balance}'); // Balance: 1500.0

  account.withdraw(200.0);
  print('Balance: ${account.balance}'); // Balance: 1300.0
}
```

**Explanation:**

* The `BankAccount` class encapsulates the properties `_accountNumber` and `_balance` by making them private.
    
* Public getters provide read-only access to the properties.
    
* Methods `deposit` and `withdraw` allow controlled modification of the balance.
    

**Diagram:**

* **Figure 4:** Encapsulation in Dart.
    
    ![Encapsulation Diagram](https://i.imgur.com/oxWzksW.png align="left")
    

---

### 5\. Small Project: Library Management System

**Project Objective:**

* Create a simple library management system using advanced OOP concepts.
    

**Project Requirements:**

* Define a `Book` class with properties like title, author, and ISBN.
    
* Define a `Member` class with properties like name, member ID, and a list of borrowed books.
    
* Define a `Library` class with methods to add books, register members, lend books, and return books.
    

**Code Implementation:**

```dart
class Book {
  String title;
  String author;
  String isbn;

  Book(this.title, this.author, this.isbn);
}

class Member {
  String name;
  String memberId;
  List<Book> borrowedBooks = [];

  Member(this.name, this.memberId);

  void borrowBook(Book book) {
    borrowedBooks.add(book);
  }

  void returnBook(Book book) {
    borrowedBooks.remove(book);
  }
}

class Library {
  List<Book> books = [];
  List<Member> members = [];

  void addBook(Book book) {
    books.add(book);
  }

  void registerMember(Member member) {
    members.add(member);
  }

  void lendBook(String isbn, String memberId) {
    Book? book = books.firstWhere((book) => book.isbn == isbn, orElse: () => null);
    Member? member = members.firstWhere((member) => member.memberId == memberId, orElse: () => null);

    if (book != null && member != null) {
      member.borrowBook(book);
      books.remove(book);
      print('${member.name} borrowed ${book.title}');
    } else {
      print('Book or Member not found');
    }
  }

  void returnBook(String isbn, String memberId) {
    Member? member = members.firstWhere((member) => member.memberId == memberId, orElse: () => null);

    if (member != null) {
      Book? book = member.borrowedBooks.firstWhere((book) => book.isbn == isbn, orElse: () => null);
      if (book != null) {
        member.returnBook(book);
        books.add(book);
        print('${member.name} returned ${book.title}');
      } else {
        print('Book not found in borrowed books');
      }
    } else {
      print('Member not found');
    }
  }
}

void main() {
  // Create library instance
  Library library = Library();

  // Add books to library
  library.addBook(Book('Dart Programming', 'John Doe', '123'));
  library.addBook(Book('Flutter Development', 'Jane Smith', '456'));

  // Register members
  library.registerMember(Member('Alice', '001'));
  library.registerMember(Member('Bob', '002'));

  // Lend and return books
  library.lendBook('123', '001');
  library.returnBook('123', '001');
}
```

**Explanation:**

* The `Book` class represents a book with properties `title`, `author`, and `isbn`.
    
* The `Member` class represents a library member with properties `name`, `memberId`, and a list of borrowed books. It has methods to borrow and return books.
    
* The `Library` class manages the collection of books and members. It has methods to add books, register members, lend books, and return books.
    
* The `main` function demonstrates adding books to the library, registering members, lending books, and returning books.
    

**Diagram:**

* **Figure 5:** Class Diagram for Library Management System.
    
    ![Class Diagram](https://i.imgur.com/CJZ8FbA.png align="left")
    

By practicing these advanced OOP concepts, you will gain a deeper understanding of how to structure and organize your Dart programs effectively. Happy coding!
