Design Pattern and Refactoring
Design Pattern
Design Pattern merupakan solusi secara general untuk mengatasi masalah yang sering tejadi dalam desain perangkat lunak. Dengan menggukan design pattern kita dapat mempercepat proses pengembangan dengan menggunakan paradigma pengembangan yang sudah teruji dan terbukti. Selain itu, dengan menggunakan design patter kita dapat mencegah masalah yang kecil menjadi besar.
Secara garis besar, terdapat tiga tipe design pattern yaitu creational, structural, dan behavioral
Creational
Design pattern tipe ini berhubungan dengan insialisasi sebuah kelas. Design pattern yang merupakan tipe creational antara lain:
- Abstract Factory
Membuat instance dari beberapa families of class
- Builder
Memisahkan object construction dengan objeknya
- Factory Method
Membuat instance dari beberapa child class
- Prototype
Membuat sebuah instance yang fully initialized untuk dikloning
- Singleton
Sebuah class hanya boleh memiliki satu instance
Structural
Design pattern tipe structural berhubungan tentang komposisi(struktur) class dan objek. Design pattern yang merupakan tipe structural antara lain:
- Adapter
Membuat sebuah interface yang dapat menghubungkan class satu dengan class lainnya
- Bridge
Memisahkan interface objek dari implementasinya
- Composite
Merupakan sebuah struktur tree dari simple dan composite objek
- Decorator
Menambahkan responsibility kepada sebuah objek secara dinamis
- Facade
Sebuah class dapat merepresentasikan seluruh subsistem
- Flyweight
Membuat instance yang ringan dan digunakan secara efisien secara bersama
Behavioral
Design pattern tipe ini behubungan tentang komunikasi(perilaku/behavior) sebuah class dengan class lainnya. Design pattern yang merupakan tipe behavioral antara lain:
- Chain of responsibility
Melakukan passing request antara serangkaian object
- Command
Melakukan enkapsulasi dengan cara menjadikan command request menjadi object
- Iterator
Mengakses seluruh elemen pada sebuah struktur data secara berurutan
- Memento
Menyimpan state sebuah objek yang nantinya akan digunakan untuk melakukan proses undo
- Observer
Sebuah cara untuk memberitahu perubahan yang terjadi kepada sejumlah class
- Strategy
Melakukan enkapsulasi algoritma menjadi sebuah class
Selain tiga tipe pattern utama yang telah disebutkan diatas, masih ada satu tipe design pattern lainnya yaitu compound pattern. Compound pattern merupakan penggabungan dari beberapa design pattern.
Penerapan Design Pattern Pada Pengembangkan AdHub
Dalam mengembangkan perangkat lunak AdHub kami memanfaat compound design patter yaitu MVC(Model View Controller). MVC merupakan gabungan dari observer, composite, dan strategy pattern. Berikut merupakan implementasi kami
- Model
class PemasangIklan(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
full_name = models.CharField(max_length=30)
telepon = models.CharField(max_length=12)
customer_id = models.CharField(max_length=12, default='0')
class Iklan(models.Model):
id = models.AutoField(primary_key=True)
judul = models.CharField(max_length=100)
platform = models.IntegerField(choices=PLATFORM_IKLAN)
tanggal_mulai = models.DateTimeField()
tanggal_berakhir = models.DateTimeField()
deskripsi = models.TextField()
image = models.ImageField(upload_to='static/saved_image')
link_iklan = models.URLField()
pemasang_iklan = models.ForeignKey(User, on_delete=models.CASCADE)
nama_usaha = models.CharField(max_length=20)
class Pembayaran(models.Model):
id = models.OneToOneField(Iklan, primary_key=True, on_delete=models.CASCADE)
status = models.CharField(max_length=20)
total = models.IntegerField()
pemasang_iklan = models.ForeignKey(User, on_delete=models.CASCADE)
bank_pengirim = models.CharField(max_length=10, null=True)
no_rekening = models.CharField(max_length=20, null=True)
bukti = models.ImageField(null=True)
- View
{% extends "base-authenticated.html" %}
{% load staticfiles %}
{% load static %}
{% block content %}
<div class="container">
{% include "container/new_ad/platform.html" %}
</div>
{% endblock %}
- Controller
def iklan_index(request):
response['title'] = 'Adhub'
return render(request, 'platform.html', response)
@csrf_exempt
def set_cookie(request):
check = dict(request.POST.lists())
platform = check["platform[]"]
response = HttpResponse("cookie set")
response.set_cookie('platform', platform, expires=2 * 60 * 60)
return response
Refactoring
“The process of changing a software system in such a way that it does not alter the external behaviour of the code yet improves the internal structure.”
Refactoring merupakan sebuah proses melakukan perubahan internal perangkat lunak sehingga menjadi lebih baik, mudah untuk dipahami, dan mudah dimodifikasi tanpa mengubahan perilaku kode.
Kanapa kita harus melakukan refactoring?
- Refactoring meningkatkan desain perangkat lunak
- Refactoring membuat perangkat lunak lebih mudah dipahami
- Refactoring membantu kita menemukan bug
- Refactoring membantu kita memprogram lebih cepat
Kapan kita harus melakukan refactoring?
- Refactoring saat kita menambahkan fungsi
- Refactoring saat kita perlu memperbaiki bug
- Refactoring saat kita melakukan review kode
Extract Method
Apabila kita memiliki bagian kode yang dapat dikelompokkan bersama maka kita ubah bagian kode tersebut menjadi method yang memiliki nama yang menjelaskan tujuan method tersebut. Sebagai contoh
#Sebelum extract method
Class Customer(
public String statement() {
double totalAmount = 0;
int frequentRenterPoints = 0;
Iterator<Rental> iterator = rentals.iterator();
String result = "Rental Record for " + getName() + "\n";
while (iterator.hasNext()) {
Rental each = iterator.next();
double thisAmount = 0;
// Determine amount for each line
switch (each.getMovie().getPriceCode()) {
case Movie.REGULAR:
thisAmount += 2;
if (each.getDaysRented() > 2)
thisAmount += (each.getDaysRented() - 2) * 1.5;
break;
case Movie.NEW_RELEASE:
thisAmount += each.getDaysRented() * 3;
break;
case Movie.CHILDREN:
thisAmount += 1.5;
if (each.getDaysRented() > 3)
thisAmount += (each.getDaysRented() - 3) * 1.5;
break;
}
// Add frequent renter points
frequentRenterPoints++;
// Add bonus for a two day new release rental
if ((each.getMovie().getPriceCode() == Movie.NEW_RELEASE) &&
each.getDaysRented() > 1)
frequentRenterPoints++;
// Show figures for this rental
result += "\t" + each.getMovie().getTitle() + "\t" +
String.valueOf(thisAmount) + "\n";
}
result += "Amount owed is " + String.valueOf(totalAmount) + "\n";
result += "You earned " + String.valueOf(frequentRenterPoints) + " frequent renter points";
return result;}
Dilakukan extract method pada statment
#Sesudah extract method
class Customer {
public String statement() {
Iterator<Rental> iterator = rentals.iterator();
String result = "Rental Record for " + getName() + "\n";
while (iterator.hasNext()) {
Rental each = iterator.next();
// Show figures for this rental
result += "\t" + each.getMovie().getTitle() + "\t"
+ String.valueOf(each.getCharge()) + "\n";
}
// Add footer lines
result += "Amount owed is " + String.valueOf(getTotalCharge()) + "\n";
result += "You earned " + String.valueOf(getTotalFrequentRenterPoints())
+ " frequent renter points";
return result;
} private double getTotalCharge(){
double result = 0;
Iterator<Rental> iterator = rentals.iterator();
while (iterator.hasNext()){
Rental each = iterator.next();
result += each.getCharge();
}
return result;
}
// Add frequent renter points
private int getTotalFrequentRenterPoints(){
int result = 0;
Iterator<Rental> iterator = rentals.iterator();
while (iterator.hasNext()){
Rental each = iterator.next();
result += each.getFrequentRenterPoints();
}
return result;
}
}
Move Method
Apabila sebuah method lebih banyak digunakan oleh class lain maka kita dapat membuat method baru dengan body serupa di class yang paling banyak menggunakannya.
Replace Temp with Query
Apabila kita menggunakan temporary variable(temp) untuk menyimpan sebuah nilai maka kita extract ekpresi temp tersebut menjadi method.