OOP Tasarımı, mevcut tasarımda hiçbir değişiklik yapılmadığını düşünür
Soru:
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();
}
}
Gerekli olan, arayüzü ve sınıfın kendisini değiştirmeden eat yönteminin kaç kez çağrıldığını hesaplamaktır.
Bunun bir yolu, aslan sınıfını genişletmek ve sonuçları elde etmektir, ancak sınıfı genişleten her nesne için bu tür sınıflar oluşturmamız gerekecek.
Bunu yapmanın optimize edilmiş bir yolu var mı?
Yayınlama Aboneliği bir yoldur, ancak arayüzü veya Lion sınıfının kendisini değiştirme iznine sahip değiliz.
Yanıtlar
Alt sınıflandırma yapmadan bir Hayvana ek sorumluluklar eklemek için Dekoratör Modeli'ni kullanabilirsiniz.

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());
}
}
GÜNCELLEME
Dekoratör Modeline daha sadık olmak istiyorsak, getEatCount()
alıcıyı hiç kullanamayız ve bunun yerine yapıcıya bir Sayaç nesnesi enjekte ederiz .
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());
}
}

Kompozisyon için mükemmel bir zaman. Bunun yeni bir uygulamasını oluşturun Animal
, ancak saymayı yapar, ancak aynı zamanda "gerçek" işlevi delege eder. Bunun gibi:
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
}
}
Mevcut sınıflardan herhangi birini değiştirmeniz gerekmez ve Animal
bunu istediğiniz herhangi bir uygulama ile birleştirebilirsiniz . Bu şekilde kullanın:
Animal lion = new LoggingAnimal(new Lion());
lion.eat();
Yeni davranışla yeni bir sınıf oluşturun. Ardından güncelleme main
de Test
sınıfta.
class Test {
public static void main(String[] args) {
Animal lion = new AnimalThatKeepsAMealLog();
lion.eat();
lion.eat();
lion.eat();
}
}
veya sadece Test dosyasını okuyun ve kaç kez aradığınızı sayın eat()
. Tahminimce cevap üç olacak.
Sadece birkaç kez yapılan görevler için 50 sınıftan kaçınmanıza izin verecek farklı bir yaklaşım. Daha genel bir yöntemdir, teknik açıdan çok yararlıdır, iş dünyasında olduğu kadar değil, yine de çok yararlı olabilir.
btw Builder sadece göstermek içindir, tabii ki bu şekilde kullanmak zorunda değilsiniz, burada preEat / postEat önemlidir
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());
}
}