Quiz
Soal
!Soal
Essay
1. Definisi dan Kategorisasi Design Pattern
a.
Design pattern adalah solusi umum yang dapat digunakan kembali untuk menyelesaikan masalah yang sering terjadi dalam perancangan perangkat lunak. Design pattern bukanlah template yang langsung dapat diubah menjadi kode, melainkan merupakan pola atau template untuk memecahkan masalah yang dapat digunakan dalam berbagai situasi berbeda. Design pattern menyediakan cara standar untuk memecahkan masalah umum dalam pengembangan software dan membantu membuat kode lebih mudah dipelihara, fleksibel, dan dapat digunakan kembali.
b.
- Creational Patterns
- Berfokus pada mekanisme pembuatan objek
- Mengenkapsulasi pengetahuan tentang kelas konkret yang digunakan sistem
- Contoh:
- Factory Method (membuat objek tanpa mengekspos logika pembuatan)
- Singleton (memastikan kelas hanya memiliki satu instance)
- Builder (memisahkan konstruksi objek kompleks dari representasinya)
- Structural Patterns
- Berkaitan dengan komposisi kelas dan objek untuk membentuk struktur yang lebih besar
- Membantu memastikan ketika satu bagian sistem berubah, seluruh sistem tidak perlu berubah
- Contoh:
- Adapter (menghubungkan interface yang tidak kompatibel)
- Decorator (menambah fungsi pada objek secara dinamis)
- Behavioral Patterns
- Berfokus pada interaksi antar objek
- Menentukan pola interaksi antar objek dan mendistribusikan tanggung jawab
- Contoh:
- Observer (mendefinisikan ketergantungan one-to-many antar objek)
- Strategy (mendefinisikan family algoritma yang dapat dipertukarkan)
- Command (mengenkapsulasi request sebagai objek)
2. Design Pattern vs Framework
| Design Pattern | Framework |
|---|---|
| Konsep desain yang memberikan solusi untuk masalah umum | Implementasi konkret yang dapat langsung digunakan |
| Lebih kecil dan spesifik dalam lingkup | Memiliki lingkup yang lebih luas dan kompleks |
| Dapat diimplementasikan dalam berbagai bahasa pemrograman | Biasanya spesifik untuk bahasa pemrograman tertentu |
| Tidak memiliki kode yang dapat langsung dieksekusi | Memiliki kode yang dapat langsung digunakan |
| Contoh: | |
| Express.js digunakan sebagai framework untuk menangani request dan routing, sementara Factory Method Pattern digunakan untuk membuat objek notifikasi (email atau SMS). Express.js menyediakan endpoint '/notify' yang menerima tipe notifikasi dan pesan, kemudian menggunakan NotificationFactory untuk membuat objek notifikasi yang sesuai. |
const express = require('express');
const app = express();
app.use(express.json());
// DESIGN PATTERN: Factory Method (Simple)
class NotificationFactory {
createNotification(type) {
if (type === 'EMAIL') {
return new EmailNotification();
} else if (type === 'SMS') {
return new SMSNotification();
}
}
}
class EmailNotification {
send(message) {
return `Sending email: ${message}`;
}
}
class SMSNotification {
send(message) {
return `Sending SMS: ${message}`;
}
}
const notificationFactory = new NotificationFactory();
// EXPRESS FRAMEWORK: Routing
app.post('/notify', (req, res) => {
const { type, message } = req.body;
const notification = notificationFactory.createNotification(type);
const result = notification.send(message);
res.json({ result });
});
app.listen(3000, () => {
console.log('Server running on port 3000');
});
// POST http://localhost:3000/notify
// Body: {
// "type": "EMAIL",
// "message": "Hello World"
// }
3. Prinsip Fundamental Design Pattern
a. Interface
Sebuah kontrak yang dapat diimplementasikan oleh class. Interface mendefinisikan method apa saja yang harus diimplementasikan oleh class yang menggunakannya.
Contoh:
Misal ada dua buah metode pembayaran yaitu CreditCard and PayPal. Kedua metode tersebut memiliki class sendiri yang mengimplementasikan interface Payment sehingga keduanya dipastikan memiliki method pay.
public interface PaymentMethod {
void pay(double amount);
}
public class CreditCard implements PaymentMethod {
@Override
public void pay(double amount) {
System.out.println("Paid " + amount + " using Credit Card.");
}
}
public class PayPal implements PaymentMethod {
@Override
public void pay(double amount) {
System.out.println("Paid " + amount + " using PayPal.");
}
}
b. Composition
Sebuah prinsip dimana sebuah class terdiri dari satu atau lebih object dari class lain. Composition membuat code menjadi lebih fleksibel karena masing-masing object yang membentuk sebuah class, loosely coupled sehingga mudah melakukan perubahan.
Contoh:
Misal ada sebuah class Car yang menggunakan Engine. Dengan menggunakan composition dan bukan inheritance maka Car yang memiliki object class Engine tidak perlu banyak melakukan perubahan jika ada yang perlu diubah pada class Engine.
public class Engine {
public void start() {
System.out.println("Engine started.");
}
}
public class Car {
private Engine engine;
public Car() {
this.engine = new Engine();
}
public void startCar() {
engine.start();
System.out.println("Car started.");
}
}
c. Delegation
Sebuah prinsip dimana sebuah class memberikan tanggung jawabnya ke sebuah class helper. Daripada melakukan fungsi sendiri, objek tersebut mendelegasikan tugas ke objek lain yang lebih khusus. Delegation memudahkan dalam menggunakan ulang code dan memisahkan tanggung jawab.
Contoh:
Class Gallery mendelegasikan tugas render gambar ke kelas ImageRenderer melalui objek renderer. Dengan memiliki instance ImageRenderer, Gallery dapat mendelegasikan tugas tanpa perlu mengetahui detail implementasinya.
// Delegate
public class ImageRenderer {
public void render(String image) {
System.out.println("Rendering image: " + image);
}
}
// Delegator
public class Gallery {
private ImageRenderer renderer = new ImageRenderer(); // Delegation
public void displayImage(String image) {
renderer.render(image); // Delegate rendering to ImageRenderer
}
}
public class Main {
public static void main(String[] args) {
Gallery gallery = new Gallery();
gallery.displayImage("picture.jpg");
}
}
4. Factory Method Pattern
a.
- Product
Interface atau abstract class yang mendefinisikan objek yang akan dibuat - Concrete Product
Implementasi spesifik dari Product - Creator
Abstract class yang mendeklarasikan factory method - Concrete Creator
Kelas yang mengimplementasikan factory method
b.
Simple Factory:
- Hanya satu factory method
- Lebih sederhana untuk kasus sederhana
- Contoh:
public class SimplePaymentFactory {
public Payment createPayment(String type) {
if (type.equals("CREDIT")) {
return new CreditPayment();
} else if (type.equals("DEBIT")) {
return new DebitPayment();
}
return null;
}
}
Abstract Factory:
- Multiple factory methods
- Lebih kompleks tapi lebih fleksibel
- Cocok untuk families of related objects
public interface PaymentFactory {
Payment createPayment();
Receipt createReceipt();
}
public class CreditCardFactory implements PaymentFactory {
public Payment createPayment() {
return new CreditPayment();
}
public Receipt createReceipt() {
return new CreditReceipt();
}
}
Case
Soal 1
1

2
- OCP
Jika mau menambahkan jenis denda baru maka classLibraryTransactionharus dimodifikasi. Karena classLibraryTransactionmenambahkan fungsionalitas apapun akan mengharuskan merubah classLibraryTransaction. - SRP
ClassLibraryTranscationmenangani terlalu banyak tanggung jawab, seperti peminjaman, pengembalian, dan perhitungan denda.
3
Pada class diagram yang baru ini tanggung jawab perhitungan denda dipindahkan menjadi sebuah interface sendiri sehingga memudahkan jika ingin menambahkan tipe denda baru karena tidak perlu mengubah seluruh class LibraryTransaction.

Soal 2
1
Class AirShiping inherit dari LandShipping tetapi implementasi perhitungan biaya berbeda, LandShipping menggunakan berat sedangkan AirShipping menggunakan berat dan volume. Perbedaan logic antara hubungan parent and child adalah pelanggaran LSP (is-a). AirShipping tidak bisa digunakan sebagai pengganti LandShipping karena hasil perhitungan akan tidak konsisten dan kemungkinan besar salah karena adanya perbedaan logic perhitungan.
2
Karena kedua class tersebut memiliki logic yang berbeda tetapi memiliki hubungan parent and child maka masalah yang dapat muncul adalah ketika penggunaan bisa saja salah menggunakan dimana seharusnya menggunakan LandShipping tetapi karena AirShipping merupakan childnya maka secara code bisa digunakan. Hal tersebut menyebabkan kesalahan dalam perhitungan pada program yang dibuat.
3
Dengan memisahkannya dan membuat keduanya menjadi child dari interface yang sama maka kedua class tersebut tetap sejenis namun tidak saling mewariskan apapun. Karena memiliki interface yang general maka kedepannya dapat ditambahkan sebuah metode shipping baru tanpa harus mengubah banyak codenya jika dibandingkan diagram pertama.

Soal 3
1
Pelanggaran ISP terjadi karena BankTransferPayment inherit dari interface PaymentProcessor. Pada PaymentProcessor ada method authorizePayment(), sedangkan BankTransferPayment tidak menggunakan method tersebut. Hal tersebut berarti PaymentProcessor tidak bisa diterapkan untuk semua metode pembayaran.
2
Pelanggaran DIP terjadi karena PaymentService bergantung pada class concrete yaitu CreditCardPayment dan BankTransferPayment. ketergantungan tersebut melanggar DIP karena jika ditambahkan metode pembayaran baru maka PaymentService juga harus diubah dan ketergantungannya bertambah banyak sehingga menjadi kurang fleksibel dan sulit dimodifikasi.
3
Pada class diagram yang sudah diperbaiki, sendReceipt() dan authorizePayment() dipsahkan menjadi interfacenya sendiri sehingga hanya jenis pembayaran yang membutuhkan saja yang perlu mengimplementasikan masing-masing dari interface tersebut. PaymentService juga diubah dari bergantung pada masing-masing conrete metode pembayaran, menjadi bergantung pada parent abstractnya yaitu Payment sehingga jika ada metode pembayaran baru tidak perlu mengubah PaymentService.

Soal 4
interface Transport {
double getPrice();
}
class Bus implements Transport {
@Override
public double getPrice() {
return 100000;
}
}
class Kereta implements Transport {
@Override
public double getPrice() {
return 200000;
}
}
class Pesawat implements Transport {
@Override
public double getPrice() {
return 1000000;
}
}
class TransportFactory {
public static Transport create(String type) {
switch (type.toLowerCase()) {
case "bus":
return new Bus();
case "kereta":
return new Kereta();
case "pesawat":
return new Pesawat();
default:
throw new IllegalArgumentException("unsupported");
}
}
}
class Main {
private Scanner scan = new Scanner(System.in);
public static void main(String[] args){
String type = scan.nextLine();
Transport tp = TransportFactory.create(type);
System.out.println("Transport: " + type + "\nHarga: " + tp.getPrice());
}
}