![Perbedaan Object Data Store pada OOP](https://images.ctfassets.net/7wjlcr9d5ii8/1MtVa3RyI8NRNQ74oFQ20v/55965e7cfb5d704c0c8ace36833b5825/data_store.jpeg?w=1024&h=1024&fl=progressive&q=100&fm=jpg&fit=thumb&f=faces)
Pada OOP, kita menyimpan Data Store melalui sebuah class khusus untuk menyimpan sekelompok data. Mungkin masih banyak yang bingung tentang membedakan definisi-definisi data store pada OOP. Bahkan ga jarang sering kebolak-balik menggunakan terminologinya. Biar ga bingung, gw akan bahas tentang berbagai macam data store pada OOP. Seperti biasa, gw akan mencontohkannya menggunakan Java, karena kebetulan itu bahasa yang paling sering gw pakai. Tapi harusnya ini ga hanya berlaku pada Java, juga pada bahasa OOP lainnya. Hanya beda syntax aja.
Pada Java disebut POJO (Plain Old Java Object). Intinya adalah class tersebut menyimpan data pada sebuah object. Pada Data class, tidak ada aturan strict tertentu. Yang penting class tersebut menyimpan nilai pada object. Contohnya seperti berikut:
Data Class Finance
public class Finance{
public double salary;
private double tax;
public boolean isActive;
public double showTax(){
return tax;
}
}
Pada data di atas, kita boleh membuat encapsulation-nya secara public maupun private. Constructornya juga terserah, boleh pake default, boleh juga tidak. Override method hashCode dan Equals, juga tidak wajib. Nama accessornya juga terserah kita. Yang penting isinya adalah data.
Untuk bagian ini, mungkin hanya ada pada bahasa tertentu saja. Bean adalah Data Class dengan convention. Jika pada Data Class tidak ada aturan mengikat, maka pada Bean Class terdapat beberapa aturan atau convention. Yaitu:
- Memiliki property dengan private encapsulation;
- Untuk property boolean tidak perlu menggunakan awalan “is”, misalnya property “active” tidak perlu ditulis “isActive”;
- Memiliki public getter dan setter pada setiap property sebagai accessor dan mutator;
- Getter pada property diawali dengan prefix “get{PropertyName}” dan Setter pada property diawali dengan prefix “set{PropertyName}”;
- Untuk data boolean, getter-nya boleh dengan prefix “is{PropertyName}”;
- Memiliki public default constructor (no args constructor);
- Wajib melakukan override terhadap method equals dan hashCode beserta implementasinya;
- Mengimplementasi Serializable interface;
Bean Finance
public class Finance implements Serializable{
private double salary;
private double tax;
private boolean active;
public Finance(){ }
public double getSalary(){
return salary;
}
public void setSalary(double salary){
this.salary = salary;
}
public double getTax(){
return tax;
}
public void setTax(double tax){
this.tax = tax;
}
public boolean isActive(){
return active;
}
public void setActive(boolean active){
this.active = active;
}
@Override
public boolean equals(Object o){
if(this == o) return true;
if(o == null || getClass() != o.getClass()) return false;
Finance finance = (Finance) o;
if(Double.compare(finance.salary, salary) != 0) return false;
if(Double.compare(finance.tax, tax) != 0) return false;
return active == finance.active;
}
@Override
public int hashCode(){
int result;
long temp;
temp = Double.doubleToLongBits(salary);
result = (int) (temp ^ (temp >>> 32));
temp = Double.doubleToLongBits(tax);
result = 31 * result + (int) (temp ^ (temp >>> 32));
result = 31 * result + (active ? 1 : 0);
return result;
}
}
Class di atas disebut Java Bean Class karena sudah memenuhi convention Java Bean. Pada Java, convention pada Data Class dibutuhkan oleh library untuk melakukan mapping data, seperti pada Hibernate atau MapStruct. Agar code kita support terhadap library tersebut, data class yang kita buat harus mengikuti convention Java Bean.
Value Class adalah Bean Class yang immutable. Jika pada Bean Class terdapat mutator, maka pada Value Class ga ada, melainkan hanya ada accessor saja. Syaratnya adalah:
- Memiliky property dengan private encapsulation dan harus final;
- Memiliki getter pada setiap property sebagai accessor;
- Tidak ada mutator seperti setter;
- Memiliki satu constructor dengan semua property sebagai arguments;
- Wajib melakukan override terhadap method equals dan hashCode beserta implementasinya;
- Class tersebut bersifat final sehingga tidak boleh di-extend class lain;
Value Class Finance
public final class Finance implements Serializable{
private final double salary;
private final double tax;
private final boolean active;
public Finance(double salary, double tax, boolean active){
this.salary = salary;
this.tax = tax;
this.active = active;
}
public double getSalary(){
return salary;
}
public double getTax(){
return tax;
}
public boolean isActive(){
return active;
}
@Override
public boolean equals(Object o){
if(this == o) return true;
if(o == null || getClass() != o.getClass()) return false;
Finance finance = (Finance) o;
if(Double.compare(finance.salary, salary) != 0) return false;
if(Double.compare(finance.tax, tax) != 0) return false;
return active == finance.active;
}
@Override
public int hashCode(){
int result;
long temp;
temp = Double.doubleToLongBits(salary);
result = (int) (temp ^ (temp >>> 32));
temp = Double.doubleToLongBits(tax);
result = 31 * result + (int) (temp ^ (temp >>> 32));
result = 31 * result + (active ? 1 : 0);
return result;
}
}
Jika sebelumnya kita menggunakan class sebagai data store, sekarang Java sudah menyediakan keyword khusus untuk menyimpan data. Semenjak Java 14 rilis, fitur Record menjadi pengganti Value Class sebagai tempat penyimpanan data secara immutable. Record lebih simple daripada Value Class. Contohnya seperti berikut:
Record Finance Java
public record Finance(double salary, double tax, boolean isActive){ }
Pada Record kita ga perlu bikin final class, final property, public getters, override equals dan hashCode. Kita hanya masukin masing-masing propety di belakang nama Record. Sisanya sudah otomatis dihandle oleh Java, jadi ga perlu banyak setup seperti Value Class. Selain pada Java, Record juga ada pada bahasa OOP lain seperti C# sejak versi 9.
Record Finance C#
public record Finance(double salary, double tax, bool isActive);
Record ini mirip seperti “type” pada typescript, yaitu sebagai class khusus untuk menyimpan data. Bedanya pada typescript kita masih harus memasukkan keyword “readonly” pada masing-masing property agar immutable.
Finance Type
type Finance = {
readonly salary: number;
readonly tax: number | null;
readonly active: boolean;
}
Selain itu, pada typescript kita juga bisa menggunakan interface dan dibungkus ReadOnly<> saat menggunakannya agar objek yang kita buat property-nya tidak bisa diubah.
Finance ReadOnly
interface Finance{
salary: number;
tax: number | null;
active: boolean;
}
const finance: Readonly<Finance> = {
active: true,
salary: 1000,
tax: 100,
}
Itulah masing-masing perbedaan terminology Data Store pada OOP, khususnya Java. Sebelum Java 14, kita menyimpan Data Store pada class biasa. Namun sekarang sudah ada keyword khusus untuk menyimpan Data Store yang sudah otomatis immutable meggunakan Record. Record juga terdapat pada bahasa OOP lain seperti C#. Pada Typescript kita bisa menggunakan “type”, maupun interface yang dibungkus dengan "ReadOnly<>" agar user tidak bisa mengubah value pada property secara runtime.