BAB 6: Object-Oriented Programming

BAB 6: Object-Oriented Programming (OOP)

6.1 Class dan Object

Pengenalan Class

Class adalah blueprint atau template untuk membuat object. Class mendefinisikan properti dan method yang akan dimiliki oleh object.

// Contoh class sederhana
class Person {
  // Properties (attributes)
  String name;
  int age;
  
  // Methods
  void sayHello() {
    print('Hello, my name is $name');
  }
  
  void haveBirthday() {
    age++;
    print('Happy birthday! Now I am $age years old');
  }
}

void main() {
  // Membuat object dari class Person
  var person1 = Person();
  person1.name = 'Budi';
  person1.age = 25;
  
  // Mengakses method
  person1.sayHello();
  person1.haveBirthday();
}

Properties dan Methods

class Car {
  // Properties
  String brand;
  String model;
  int year;
  int _mileage = 0;  // Private property
  
  // Getter
  int get mileage => _mileage;
  
  // Setter
  set mileage(int value) {
    if (value >= 0) {
      _mileage = value;
    }
  }
  
  // Method
  void drive(int kilometers) {
    if (kilometers > 0) {
      _mileage += kilometers;
      print('Driving $kilometers km. Total mileage: $_mileage');
    }
  }
  
  // Method dengan return value
  String getInfo() {
    return '$year $brand $model';
  }
}

6.2 Constructor

Default Constructor

class Student {
  String name;
  int age;
  
  // Default constructor
  Student(this.name, this.age);
  
  void introduce() {
    print('Hi, I am $name and I am $age years old');
  }
}

Named Constructor

class Rectangle {
  double width;
  double height;
  
  // Regular constructor
  Rectangle(this.width, this.height);
  
  // Named constructor
  Rectangle.square(double size)
      : width = size,
        height = size;
        
  // Named constructor with initializer list
  Rectangle.fromMap(Map<String, double> map)
      : width = map['width'] ?? 0,
        height = map['height'] ?? 0;
        
  double get area => width * height;
}

void main() {
  var rect1 = Rectangle(10, 5);
  var rect2 = Rectangle.square(10);
  var rect3 = Rectangle.fromMap({'width': 10, 'height': 5});
}

Factory Constructor

class Database {
  static Database? _instance;
  
  // Private constructor
  Database._internal() {
    print('Database initialized');
  }
  
  // Factory constructor
  factory Database() {
    return _instance ??= Database._internal();
  }
}

6.3 Inheritance

Basic Inheritance

// Base/Parent class
class Animal {
  String name;
  
  Animal(this.name);
  
  void makeSound() {
    print('Some generic sound');
  }
}

// Child class
class Dog extends Animal {
  Dog(String name) : super(name);
  
  // Method overriding
  @override
  void makeSound() {
    print('Woof!');
  }
  
  // Additional method
  void fetch() {
    print('$name is fetching the ball');
  }
}

// Another child class
class Cat extends Animal {
  Cat(String name) : super(name);
  
  @override
  void makeSound() {
    print('Meow!');
  }
}

Abstract Class

abstract class Shape {
  // Abstract method (no implementation)
  double getArea();
  double getPerimeter();
  
  // Regular method with implementation
  void printInfo() {
    print('Area: ${getArea()}');
    print('Perimeter: ${getPerimeter()}');
  }
}

class Circle extends Shape {
  double radius;
  
  Circle(this.radius);
  
  @override
  double getArea() => 3.14 * radius * radius;
  
  @override
  double getPerimeter() => 2 * 3.14 * radius;
}

6.4 Encapsulation

Private Members dan Getters/Setters

class BankAccount {
  String _accountNumber;
  double _balance = 0;
  
  BankAccount(this._accountNumber);
  
  // Getter
  double get balance => _balance;
  String get accountNumber => _accountNumber;
  
  // Method untuk deposit
  void deposit(double amount) {
    if (amount > 0) {
      _balance += amount;
      print('Deposited: \$${amount.toStringAsFixed(2)}');
      print('New balance: \$${_balance.toStringAsFixed(2)}');
    }
  }
  
  // Method untuk withdrawal
  bool withdraw(double amount) {
    if (amount > 0 && amount <= _balance) {
      _balance -= amount;
      print('Withdrawn: \$${amount.toStringAsFixed(2)}');
      print('New balance: \$${_balance.toStringAsFixed(2)}');
      return true;
    }
    print('Insufficient funds');
    return false;
  }
}

6.5 Praktek: Program Sistem Perpustakaan Sederhana

import 'dart:io';

// Class untuk merepresentasikan buku
class Book {
  String id;
  String title;
  String author;
  bool isAvailable;
  DateTime? borrowedDate;
  String? borrowedBy;

  Book(this.id, this.title, this.author) : isAvailable = true;

  // Method untuk meminjam buku
  bool borrow(String memberName) {
    if (isAvailable) {
      isAvailable = false;
      borrowedDate = DateTime.now();
      borrowedBy = memberName;
      return true;
    }
    return false;
  }

  // Method untuk mengembalikan buku
  void returnBook() {
    isAvailable = true;
    borrowedDate = null;
    borrowedBy = null;
  }

  // Method untuk menampilkan info buku
  void displayInfo() {
    print('ID: $id');
    print('Judul: $title');
    print('Penulis: $author');
    print('Status: ${isAvailable ? "Tersedia" : "Dipinjam"}');
    if (!isAvailable) {
      print('Dipinjam oleh: $borrowedBy');
      print('Tanggal pinjam: ${_formatDate(borrowedDate!)}');
    }
  }

  String _formatDate(DateTime date) {
    return '${date.day}/${date.month}/${date.year}';
  }
}

// Class untuk merepresentasikan member perpustakaan
class LibraryMember {
  String id;
  String name;
  List<Book> borrowedBooks;

  LibraryMember(this.id, this.name) : borrowedBooks = [];

  void displayInfo() {
    print('ID Member: $id');
    print('Nama: $name');
    print('Jumlah buku dipinjam: ${borrowedBooks.length}');
  }
}

// Class utama untuk manajemen perpustakaan
class Library {
  List<Book> _books = [];
  List<LibraryMember> _members = [];

  // Menambah buku baru
  void addBook(String title, String author) {
    String id = 'B${_books.length + 1}';
    _books.add(Book(id, title, author));
    print('\n✓ Buku berhasil ditambahkan!');
  }

  // Menambah member baru
  void addMember(String name) {
    String id = 'M${_members.length + 1}';
    _members.add(LibraryMember(id, name));
    print('\n✓ Member berhasil ditambahkan!');
  }

  // Menampilkan semua buku
  void displayBooks() {
    if (_books.isEmpty) {
      print('\nBelum ada buku di perpustakaan');
      return;
    }

    print('\n=== DAFTAR BUKU ===');
    for (var book in _books) {
      print('\n-------------------');
      book.displayInfo();
    }
  }

  // Menampilkan semua member
  void displayMembers() {
    if (_members.isEmpty) {
      print('\nBelum ada member terdaftar');
      return;
    }

    print('\n=== DAFTAR MEMBER ===');
    for (var member in _members) {
      print('\n-------------------');
      member.displayInfo();
    }
  }

  // Meminjam buku
  void borrowBook(String bookId, String memberId) {
    var book = _findBook(bookId);
    var member = _findMember(memberId);

    if (book == null) {
      print('\nBuku tidak ditemukan!');
      return;
    }

    if (member == null) {
      print('\nMember tidak ditemukan!');
      return;
    }

    if (book.borrow(member.name)) {
      member.borrowedBooks.add(book);
      print('\n✓ Buku berhasil dipinjam!');
    } else {
      print('\nBuku tidak tersedia untuk dipinjam!');
    }
  }

  // Mengembalikan buku
  void returnBook(String bookId, String memberId) {
    var book = _findBook(bookId);
    var member = _findMember(memberId);

    if (book == null || member == null) {
      print('\nBuku atau member tidak ditemukan!');
      return;
    }

    if (!book.isAvailable && book.borrowedBy == member.name) {
      book.returnBook();
      member.borrowedBooks.remove(book);
      print('\n✓ Buku berhasil dikembalikan!');
    } else {
      print('\nBuku tidak dapat dikembalikan!');
    }
  }

  // Helper methods
  Book? _findBook(String id) {
    return _books.firstWhere((book) => book.id == id,
        orElse: () => throw 'Book not found');
  }

  LibraryMember? _findMember(String id) {
    return _members.firstWhere((member) => member.id == id,
        orElse: () => throw 'Member not found');
  }
}

void main() {
  var library = Library();

  while (true) {
    print('\n=== SISTEM PERPUSTAKAAN ===');
    print('1. Tambah Buku');
    print('2. Tambah Member');
    print('3. Lihat Daftar Buku');
    print('4. Lihat Daftar Member');
    print('5. Pinjam Buku');
    print('6. Kembalikan Buku');
    print('7. Keluar');

    stdout.write('\nPilih menu (1-7): ');
    String? input = stdin.readLineSync();

    switch (input) {
      case '1':
        stdout.write('\nJudul buku: ');
        String? title = stdin.readLineSync();
        stdout.write('Penulis: ');
        String? author = stdin.readLineSync();
        if (title != null && author != null) {
          library.addBook(title, author);
        }

      case '2':
        stdout.write('\nNama member: ');
        String? name = stdin.readLineSync();
        if (name != null) {
          library.addMember(name);
        }

      case '3':
        library.displayBooks();

      case '4':
        library.displayMembers();

      case '5':
        stdout.write('\nID Buku: ');
        String? bookId = stdin.readLineSync();
        stdout.write('ID Member: ');
        String? memberId = stdin.readLineSync();
        if (bookId != null && memberId != null) {
          library.borrowBook(bookId, memberId);
        }

      case '6':
        stdout.write('\nID Buku: ');
        String? bookId = stdin.readLineSync();
        stdout.write('ID Member: ');
        String? memberId = stdin.readLineSync();
        if (bookId != null && memberId != null) {
          library.returnBook(bookId, memberId);
        }

      case '7':
        print('\nTerima kasih telah menggunakan Sistem Perpustakaan!');
        return;

      default:
        print('\nMenu tidak valid!');
    }
  }
}

Latihan Mandiri

  1. Tambahkan fitur untuk mengedit informasi buku dan member

  2. Implementasikan sistem denda untuk keterlambatan pengembalian

  3. Tambahkan fitur pencarian buku berdasarkan judul atau penulis

  4. Buat sistem reservasi buku yang sedang dipinjam

  5. Implementasikan fitur untuk melihat history peminjaman

Tips OOP

  1. Gunakan private members (diawali dengan _) untuk encapsulation

  2. Manfaatkan inheritance untuk mengurangi duplikasi kode

  3. Gunakan abstract class untuk template yang akan diimplementasikan

  4. Pilih constructor yang sesuai dengan kebutuhan

  5. Validasi input di constructor atau setter

  6. Gunakan getter/setter untuk akses kontrol yang lebih baik

  7. Dokumentasikan kode dengan baik

  8. Terapkan prinsip Single Responsibility

Last updated