saindras

pbo-pertemuan-9-2

Oct 28th, 2025
295
0
Never
1
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 15.88 KB | None | 0 0
  1. from abc import ABC, abstractmethod
  2. from datetime import datetime, timedelta
  3. from enum import Enum
  4. import uuid
  5.  
  6. # ==============================================================================
  7. # Definisi Enum untuk Status
  8. # ==============================================================================
  9.  
  10. class StatusItem(Enum):
  11.     """Enum untuk status item di perpustakaan."""
  12.     TERSEDIA = "Tersedia"
  13.     DIPINJAM = "Dipinjam"
  14.     HILANG = "Hilang"
  15.  
  16. class StatusTransaksi(Enum):
  17.     """Enum untuk status transaksi peminjaman."""
  18.     AKTIF = "Aktif"
  19.     SELESAI = "Selesai"
  20.     TERLAMBAT = "Terlambat"
  21.  
  22. # ==============================================================================
  23. # Hierarki Kelas Item Pustaka (LoanableItem, Buku, Majalah)
  24. # ==============================================================================
  25.  
  26. class LoanableItem(ABC):
  27.     """
  28.    Kelas abstrak untuk semua item yang dapat dipinjam di perpustakaan.
  29.    Ini adalah superclass (induk) untuk Buku, Majalah, dll.
  30.    """
  31.     def __init__(self, item_id: str, judul: str):
  32.         self._item_id = item_id
  33.         self._judul = judul
  34.         self._status = StatusItem.TERSEDIA
  35.  
  36.     @abstractmethod
  37.     def get_info(self) -> dict:
  38.         """Metode abstrak untuk mendapatkan informasi detail dari item."""
  39.         pass
  40.  
  41.     def ubah_status(self, status_baru: StatusItem):
  42.         """Mengubah status ketersediaan item."""
  43.         self._status = status_baru
  44.         print(f"INFO: Status '{self._judul}' telah diubah menjadi {status_baru.value}.")
  45.  
  46.     @property
  47.     def item_id(self):
  48.         return self._item_id
  49.  
  50.     @property
  51.     def judul(self):
  52.         return self._judul
  53.  
  54.     @property
  55.     def status(self):
  56.         return self._status
  57.  
  58. class Buku(LoanableItem):
  59.     """Kelas turunan untuk merepresentasikan sebuah buku."""
  60.     def __init__(self, item_id: str, judul: str, pengarang: str):
  61.         super().__init__(item_id, judul)
  62.         self._pengarang = pengarang
  63.  
  64.     def get_info(self) -> dict:
  65.         """Implementasi spesifik untuk menampilkan info buku (method overriding)."""
  66.         return {
  67.             "ID": self._item_id,
  68.             "Judul": self._judul,
  69.             "Tipe": "Buku",
  70.             "Pengarang": self._pengarang,
  71.             "Status": self._status.value
  72.         }
  73.  
  74. class Majalah(LoanableItem):
  75.     """Kelas turunan untuk merepresentasikan sebuah majalah/jurnal."""
  76.     def __init__(self, item_id: str, judul: str, edisi: str):
  77.         super().__init__(item_id, judul)
  78.         self._edisi = edisi
  79.  
  80.     def get_info(self) -> dict:
  81.         """Implementasi spesifik untuk menampilkan info majalah (method overriding)."""
  82.         return {
  83.             "ID": self._item_id,
  84.             "Judul": self._judul,
  85.             "Tipe": "Majalah",
  86.             "Edisi": self._edisi,
  87.             "Status": self._status.value
  88.         }
  89.  
  90. # ==============================================================================
  91. # Kelas-kelas Utama Sistem
  92. # ==============================================================================
  93.  
  94. class Member:
  95.     """Merepresentasikan anggota perpustakaan."""
  96.     def __init__(self, nama: str, alamat: str):
  97.         self._member_id = "MEM-" + str(uuid.uuid4())[:8].upper()
  98.         self._nama = nama
  99.         self._alamat = alamat
  100.  
  101.     @property
  102.     def member_id(self):
  103.         return self._member_id
  104.    
  105.     @property
  106.     def nama(self):
  107.         return self._nama
  108.  
  109.     def get_riwayat_peminjaman(self, perpus: 'Perpustakaan') -> list['Transaksi']:
  110.         """Mendapatkan daftar transaksi yang pernah dilakukan oleh member."""
  111.         riwayat = []
  112.         for transaksi in perpus.daftar_transaksi:
  113.             if transaksi.member.member_id == self._member_id:
  114.                 riwayat.append(transaksi)
  115.         return riwayat
  116.  
  117. class Transaksi:
  118.     """Merepresentasikan sebuah transaksi peminjaman."""
  119.     def __init__(self, member: Member, item: LoanableItem):
  120.         self._transaksi_id = "TRX-" + str(uuid.uuid4())[:8].upper()
  121.         self._member = member
  122.         self._item = item
  123.         self._tgl_pinjam = datetime.now()
  124.         self._tgl_kembali = self._tgl_pinjam + timedelta(days=14) # Batas peminjaman 14 hari
  125.         self._status = StatusTransaksi.AKTIF
  126.         self._denda = 0.0
  127.  
  128.     @property
  129.     def transaksi_id(self):
  130.         return self._transaksi_id
  131.  
  132.     @property
  133.     def member(self):
  134.         return self._member
  135.        
  136.     @property
  137.     def item(self):
  138.         return self._item
  139.  
  140.     @property
  141.     def status(self):
  142.         return self._status
  143.  
  144.     def hitung_denda(self) -> float:
  145.         """Menghitung denda jika pengembalian terlambat."""
  146.         if datetime.now() > self._tgl_kembali:
  147.             terlambat = (datetime.now() - self._tgl_kembali).days
  148.             self._denda = float(terlambat * 1000) # Denda 1000 per hari
  149.             self._status = StatusTransaksi.TERLAMBAT
  150.         return self._denda
  151.        
  152.     def selesaikan_transaksi(self):
  153.         self.hitung_denda()
  154.         if self._status != StatusTransaksi.TERLAMBAT:
  155.             self._status = StatusTransaksi.SELESAI
  156.  
  157. class Perpustakaan:
  158.     """Kelas utama yang mengelola seluruh sistem perpustakaan."""
  159.     def __init__(self):
  160.         self._daftar_item = []
  161.         self._daftar_member = []
  162.         self._daftar_transaksi = []
  163.         print("Sistem Perpustakaan berhasil dibuat.")
  164.  
  165.     @property
  166.     def daftar_item(self):
  167.         return self._daftar_item
  168.        
  169.     @property
  170.     def daftar_member(self):
  171.         return self._daftar_member
  172.        
  173.     @property
  174.     def daftar_transaksi(self):
  175.         return self._daftar_transaksi
  176.  
  177.     def tambah_item(self, item: LoanableItem):
  178.         """Menambahkan item baru (buku/majalah) ke perpustakaan."""
  179.         self._daftar_item.append(item)
  180.         print(f"ITEM DITAMBAHKAN: '{item.judul}' ({item.__class__.__name__}) telah ditambahkan ke koleksi.")
  181.  
  182.     def tambah_member(self, nama: str, alamat: str) -> Member:
  183.         """Mendaftarkan anggota baru."""
  184.         member_baru = Member(nama, alamat)
  185.         self._daftar_member.append(member_baru)
  186.         print(f"MEMBER BARU: {nama} dengan ID {member_baru.member_id} berhasil terdaftar.")
  187.         return member_baru
  188.  
  189.     def cari_item(self, item_id: str) -> LoanableItem | None:
  190.         """Mencari item berdasarkan ID."""
  191.         for item in self._daftar_item:
  192.             if item.item_id == item_id:
  193.                 return item
  194.         return None
  195.  
  196.     def cari_member(self, member_id: str) -> Member | None:
  197.         """Mencari member berdasarkan ID."""
  198.         for member in self._daftar_member:
  199.             if member.member_id == member_id:
  200.                 return member
  201.         return None
  202.        
  203.     def cari_transaksi(self, transaksi_id: str) -> Transaksi | None:
  204.         """Mencari transaksi berdasarkan ID."""
  205.         for trx in self._daftar_transaksi:
  206.             if trx.transaksi_id == transaksi_id:
  207.                 return trx
  208.         return None
  209.  
  210.     def pinjamkan_item(self, member_id: str, item_id: str) -> Transaksi:
  211.         """Memproses peminjaman item oleh member."""
  212.         member = self.cari_member(member_id)
  213.         item = self.cari_item(item_id)
  214.  
  215.         if not member:
  216.             raise Exception("ERROR: Member tidak ditemukan.")
  217.         if not item:
  218.             raise Exception("ERROR: Item tidak ditemukan.")
  219.         if item.status != StatusItem.TERSEDIA:
  220.             raise Exception(f"ERROR: Item '{item.judul}' sedang tidak tersedia.")
  221.  
  222.         transaksi_baru = Transaksi(member, item)
  223.         self._daftar_transaksi.append(transaksi_baru)
  224.         item.ubah_status(StatusItem.DIPINJAM)
  225.         print(f"TRANSAKSI PEMINJAMAN: '{item.judul}' dipinjam oleh {member.nama}. ID Transaksi: {transaksi_baru.transaksi_id}")
  226.         return transaksi_baru
  227.  
  228.     def terima_pengembalian(self, transaksi_id: str):
  229.         """Memproses pengembalian item."""
  230.         transaksi = self.cari_transaksi(transaksi_id)
  231.         if not transaksi:
  232.             raise Exception("ERROR: Transaksi tidak ditemukan.")
  233.         if transaksi.status != StatusTransaksi.AKTIF:
  234.             raise Exception("ERROR: Transaksi ini sudah tidak aktif.")
  235.        
  236.         transaksi.selesaikan_transaksi()
  237.         item = transaksi.item
  238.         item.ubah_status(StatusItem.TERSEDIA)
  239.        
  240.         denda = transaksi.hitung_denda()
  241.         print(f"TRANSAKSI PENGEMBALIAN: '{item.judul}' telah dikembalikan oleh {transaksi.member.nama}.")
  242.         if denda > 0:
  243.             print(f"   -> Dikenakan denda sebesar: Rp{denda:,.2f}")
  244.         else:
  245.             print("   -> Pengembalian tepat waktu.")
  246.  
  247. # Modifikasi Kelas Pustakawan
  248. class Pustakawan:
  249.     """Merepresentasikan pustakawan yang mengelola perpustakaan."""
  250.     def __init__(self, pustakawan_id: str, nama: str):
  251.         self._pustakawan_id = pustakawan_id
  252.         self._nama = nama
  253.  
  254.     def lakukan_pendaftaran(self, perpus: Perpustakaan, nama: str, alamat: str) -> Member:
  255.         """Wrapper method untuk mendaftarkan member."""
  256.         print(f"\n[Aksi Pustakawan: {self._nama}] Mendaftarkan anggota baru...")
  257.         return perpus.tambah_member(nama, alamat)
  258.  
  259.     # Ubah metode tambah_item_ke_koleksi
  260.         # def tambah_item_ke_koleksi(self, perpus: Perpustakaan, item: LoanableItem):
  261.     #    """Wrapper method untuk menambah item baru."""
  262.     #    print(f"\n[Aksi Pustakawan: {self._nama}] Menambahkan item ke koleksi...")
  263.     #    perpus.tambah_item(item)
  264.  
  265.     # Versi Baru dengan Factory
  266.     def tambah_item_ke_koleksi(self, perpus: Perpustakaan, item_type: str, item_id: str, judul: str, **kwargs):
  267.         """Wrapper method untuk menambah item baru menggunakan Factory."""
  268.         print(f"\n[Aksi Pustakawan: {self._nama}] Meminta pembuatan dan penambahan item '{judul}'...")
  269.         try:
  270.             # Panggil Factory untuk membuat objek
  271.             item_baru = ItemFactory.create_item(item_type, item_id, judul, **kwargs)
  272.             # Tambahkan objek yang sudah jadi ke perpustakaan
  273.             perpus.tambah_item(item_baru)
  274.         except ValueError as e:
  275.             print(f"ERROR saat menambah item: {e}")
  276.         except Exception as e:
  277.             print(f"ERROR tidak terduga: {e}")
  278.  
  279.     def lakukan_peminjaman(self, perpus: Perpustakaan, member_id: str, item_id: str) -> Transaksi:
  280.         """Wrapper method untuk melakukan peminjaman."""
  281.         print(f"\n[Aksi Pustakawan: {self._nama}] Memproses peminjaman...")
  282.         return perpus.pinjamkan_item(member_id, item_id)
  283.        
  284.     def lakukan_pengembalian(self, perpus: Perpustakaan, transaksi_id: str):
  285.         """Wrapper method untuk melakukan pengembalian."""
  286.         print(f"\n[Aksi Pustakawan: {self._nama}] Memproses pengembalian...")
  287.         perpus.terima_pengembalian(transaksi_id)
  288.  
  289. # Kelas Baru: ItemFactory
  290. class ItemFactory:
  291.     """Kelas Factory untuk membuat instance LoanableItem."""
  292.  
  293.     @staticmethod
  294.     def create_item(item_type: str, item_id: str, judul: str, **kwargs) -> LoanableItem:
  295.         """
  296.        Membuat objek Buku atau Majalah berdasarkan item_type.
  297.        kwargs bisa berisi 'pengarang' untuk Buku atau 'edisi' untuk Majalah.
  298.        """
  299.         if item_type.lower() == "buku":
  300.             pengarang = kwargs.get('pengarang', 'N/A') # Ambil pengarang, default N/A
  301.             if pengarang == 'N/A':
  302.                  print("WARNING: Pengarang tidak disediakan untuk buku.")
  303.             return Buku(item_id, judul, pengarang)
  304.         elif item_type.lower() == "majalah":
  305.             edisi = kwargs.get('edisi', 'N/A') # Ambil edisi, default N/A
  306.             if edisi == 'N/A':
  307.                  print("WARNING: Edisi tidak disediakan untuk majalah.")
  308.             return Majalah(item_id, judul, edisi)
  309.         # Bisa tambahkan tipe lain di sini (misal: Artikel)
  310.         # elif item_type.lower() == "artikel":
  311.         #     volume = kwargs.get('volume', 0)
  312.         #     return Artikel(item_id, judul, volume)
  313.         else:
  314.             raise ValueError(f"Tipe item tidak dikenal: {item_type}")
  315.  
  316. # ==============================================================================
  317. # CONTOH PENGGUNAAN PROGRAM (MAIN)
  318. # ==============================================================================
  319. if __name__ == "__main__":
  320.     print("===== MEMULAI SIMULASI SISTEM PERPUSTAKAAN =====")
  321.    
  322.     # 1. Inisialisasi sistem
  323.     perpustakaan_utama = Perpustakaan()
  324.  
  325.     # 2. Menambahkan pustakawan
  326.     pustakawan_andi = Pustakawan("P-001", "Andi")
  327.    
  328.     # 3. Pustakawan mendaftarkan member baru
  329.     member_budi = pustakawan_andi.lakukan_pendaftaran(perpustakaan_utama, "Budi Santoso", "Jl. Merdeka No. 10")
  330.     member_citra = pustakawan_andi.lakukan_pendaftaran(perpustakaan_utama, "Citra Lestari", "Jl. Pahlawan No. 5")
  331.  
  332.     # 4. Pustakawan menambahkan item baru (Buku dan Majalah)
  333.    
  334.     # Kode sebelumnya:
  335.     # buku_oop = Buku("BK-001", "Pemrograman Berorientasi Objek dengan Python", "Dr. Inovatif")
  336.     # majalah_sains = Majalah("MGZ-001", "Quanta Magazine", "Edisi Oktober 2025")
  337.     # buku_data = Buku("BK-002", "Sains Data untuk Pemula", "Prof. Analitika")
  338.  
  339.     # pustakawan_andi.tambah_item_ke_koleksi(perpustakaan_utama, buku_oop)
  340.     # pustakawan_andi.tambah_item_ke_koleksi(perpustakaan_utama, majalah_sains)
  341.     # pustakawan_andi.tambah_item_ke_koleksi(perpustakaan_utama, buku_data)
  342.  
  343.     # Kode baru penggunaan factory:
  344.     pustakawan_andi.tambah_item_ke_koleksi(perpustakaan_utama, "Buku", "BK-001", "OOP Python", pengarang="Dr. Inovatif")
  345.     pustakawan_andi.tambah_item_ke_koleksi(perpustakaan_utama, "Majalah", "MGZ-001", "Quanta", edisi="Okt 2025")
  346.     pustakawan_andi.tambah_item_ke_koleksi(perpustakaan_utama, "Buku", "BK-002", "Sains Data", pengarang="Prof. Analitika")
  347.     # Coba tambahkan tipe yang salah
  348.     pustakawan_andi.tambah_item_ke_koleksi(perpustakaan_utama, "Artikel", "ART-001", "Artikel Ilmiah", volume=5)
  349.    
  350.     print("\n===== STATUS AWAL KOLEKSI DAN MEMBER =====")
  351.     print("--- Daftar Item ---")
  352.     # Contoh polimorfisme saat menampilkan info
  353.     for item in perpustakaan_utama.daftar_item:
  354.         print(item.get_info())
  355.    
  356.     print("\n--- Daftar Member ---")
  357.     for member in perpustakaan_utama.daftar_member:
  358.         print(f"ID: {member.member_id}, Nama: {member.nama}")
  359.    
  360.     # 5. Simulasi Transaksi Peminjaman
  361.     print("\n===== SIMULASI TRANSAKSI =====")
  362.     try:
  363.         # Budi meminjam buku OOP
  364.         transaksi1 = pustakawan_andi.lakukan_peminjaman(perpustakaan_utama, member_budi.member_id, "BK-001")
  365.        
  366.         # Citra meminjam majalah sains
  367.         transaksi2 = pustakawan_andi.lakukan_peminjaman(perpustakaan_utama, member_citra.member_id, "MGZ-001")
  368.        
  369.         # Budi mencoba meminjam buku yang sama lagi (akan gagal)
  370.         pustakawan_andi.lakukan_peminjaman(perpustakaan_utama, member_budi.member_id, "BK-001")
  371.  
  372.     except Exception as e:
  373.         print(e)
  374.        
  375.     print("\n===== STATUS SETELAH PEMINJAMAN =====")
  376.     for item in perpustakaan_utama.daftar_item:
  377.         print(f"Judul: {item.judul}, Status: {item.status.value}")
  378.  
  379.     # 6. Simulasi Transaksi Pengembalian
  380.     try:
  381.         # Budi mengembalikan buku OOP
  382.         pustakawan_andi.lakukan_pengembalian(perpustakaan_utama, transaksi1.transaksi_id)
  383.        
  384.         # Citra mencoba mengembalikan majalah (simulasi terlambat dengan "memajukan" waktu)
  385.         transaksi2._tgl_kembali = datetime.now() - timedelta(days=3) # Anggap terlambat 3 hari
  386.         pustakawan_andi.lakukan_pengembalian(perpustakaan_utama, transaksi2.transaksi_id)
  387.  
  388.     except Exception as e:
  389.         print(e)
  390.        
  391.     print("\n===== STATUS AKHIR SETELAH PENGEMBALIAN =====")
  392.     for item in perpustakaan_utama.daftar_item:
  393.         print(f"Judul: {item.judul}, Status: {item.status.value}")
  394.        
  395.     print("\n===== RIWAYAT PEMINJAMAN BUDI =====")
  396.     riwayat_budi = member_budi.get_riwayat_peminjaman(perpustakaan_utama)
  397.     for trx in riwayat_budi:
  398.         print(f"ID: {trx.transaksi_id}, Item: '{trx.item.judul}', Status: {trx.status.value}")
  399.        
  400.     print("\n===== SIMULASI SELESAI =====")
Advertisement
Comments
Add Comment
Please, Sign In to add comment