Desain OOP mempertimbangkan tidak ada modifikasi pada desain yang sudah ada
Pertanyaannya adalah:
interface Animal {
void eat();
}
class Lion implements Animal{
public void eat(){
//do somethng
}
}
class Test {
public static void main(String[] args) {
Animal lion = new Lion();
lion.eat();
lion.eat();
lion.eat();
}
}
Persyaratannya adalah menghitung berapa kali metode makan dipanggil tanpa memodifikasi antarmuka dan kelas itu sendiri.
Salah satu caranya adalah dengan memperluas kelas singa dan mendapatkan hasil tetapi untuk setiap objek yang memperluas kelas kita harus membuat kelas seperti itu.
Apakah ada cara yang dioptimalkan untuk melakukan ini.
Publikasikan Berlangganan adalah salah satu cara tetapi kami tidak memiliki izin untuk mengubah antarmuka atau kelas Lion itu sendiri.
Jawaban
Anda dapat menggunakan Pola Dekorator untuk menambahkan tanggung jawab tambahan pada Hewan tanpa subclassing.

public interface Animal {
void eat();
}
public class Lion implements Animal {
public void eat() {
// do something
}
}
/* In the original Decorator pattern,
the decorator is an abstract class,
but for the sake of brevity,
in this example it's a concrete class. */
public class AnimalWithEatCountDecorator implements Animal {
private Animal animalWeWantToCountEats;
private int eatCount=0;
public AnimalWithEatCountDecorator(Animal animal) {
this.animalWeWantToCountEats= animal;
}
public void eat(){
this.animalWeWantToCountEats.eat();
this.eatCount++;
}
public int getEatCount() {
return this.eatCount;
}
}
public class Test {
public static void main(String[] args) {
AnimalWithEatCountDecorator lion = new AnimalWithEatCountDecorator(new Lion());
lion.eat();
lion.eat();
lion.eat();
System.out.println(lion.getEatCount());
}
}
MEMPERBARUI
Jika kita ingin lebih setia pada Pola Dekorator kita tidak bisa menggunakan getEatCount()
getter sama sekali, dan sebagai gantinya menyuntikkan objek Counter di konstruktor.
public interface Counter {
public void increment();
public int getCount();
}
/* I will omit the trivial implementation of Counter */
public class AnimalWithEatCountDecorator implements Animal {
private Animal animalWeWantToCountEats;
private Counter counterThingy;
public AnimalWithEatCountDecorator(Animal animal, Counter counterThingy) {
this.animalWeWantToCountEats= animal;
this.counterThingy=counterThingy;
}
public void eat(){
this.animalWeWantToCountEats.eat();
this.counterThingy.increment();;
}
}
public class Test {
public static void main(String[] args) {
Counter counterThingy = new CounterThingy();
AnimalWithEatCountDecorator lion =
new AnimalWithEatCountDecorator(new Lion(), counterThingy);
lion.eat();
lion.eat();
lion.eat();
System.out.println(counterThingy.getCount());
}
}

Waktu yang tepat untuk komposisi. Buat implementasi baru Animal
yang melakukan penghitungan, tetapi juga mendelegasikan fungsi "nyata". Seperti ini:
public final class LoggingAnimal implements Animal {
private final Animal delegate;
private int eatCount = 0;
public LoggingAnimal(Animal delegate) {
this.delegate = delegate;
}
@Override
public void eat() {
eatCount++;
delegate.eat();
log("Animal ate {} times", eatCount); // Pseudo-functionality
}
}
Anda tidak perlu mengubah kelas yang ada, dan Anda dapat menyambungkannya bersama dengan implementasi yang Animal
Anda inginkan. Gunakan cara ini:
Animal lion = new LoggingAnimal(new Lion());
lion.eat();
Buat kelas baru dengan perilaku baru. Kemudian perbarui main
di Test
kelas.
class Test {
public static void main(String[] args) {
Animal lion = new AnimalThatKeepsAMealLog();
lion.eat();
lion.eat();
lion.eat();
}
}
atau cukup baca file Tes dan hitung berapa kali Anda menelepon eat()
. Saya menduga jawabannya adalah tiga.
Jenis pendekatan yang berbeda, yang akan memungkinkan Anda untuk menghindari 50 kelas untuk tugas yang hanya dilakukan beberapa kali. Ini lebih umum, sangat berguna dalam aspek teknis, tidak banyak dalam bisnis, masih bisa sangat berguna.
btw Builder hanya untuk ilustrasi, tentunya tidak harus menggunakan seperti itu, preEat / postEat penting disini
class PointcutAnimal implements Animal {
private Runnable preEat;
private Runnable postEat;
@NonNull
private Animal downstream;
@Override
public void eat() {
if(preEat != null)
preEat.run();
downstream.eat();
if(postEat != null)
postEat.run();
}
}
class Test {
public static void main(String[] args) {
AtomicInteger eatCount = new AtomicInteger(0);
Animal lion = PointcutAnimal.builder(new Lion())
.postEat(eatCount::getAndIncrement)
.build();
lion.eat();
lion.eat();
lion.eat();
System.out.println(eatCount.get());
}
}