Refactoring if instanceof / else if instancecof Utilizzo del pattern visitatore

Apr 22 2023
Il modello del visitatore è uno dei modelli di progettazione comportamentale. Visitor Pattern fornisce funzionalità alla nostra struttura dall'esterno.

Il modello del visitatore è uno dei modelli di progettazione comportamentale. Visitor Pattern fornisce funzionalità alla nostra struttura dall'esterno. Quello che voglio dire è che utilizzando Visitor Pattern, fornisci alcune funzionalità al tuo progetto come funzionalità che cambiano in base al tipo di classe.

Supponiamo di avere un servizio che aggiunge dati alle pagine di PowerPoint in base a determinati tipi. Supportiamo tre tipi di testo, tabella e video. Quando abbiamo creato questa applicazione per la prima volta, abbiamo utilizzato il metodo "instanceof" per la situazione condizionale. Gli oggetti Video, Text e Table ereditano la stessa classe Parent. Abbiamo eseguito un'operazione adeguata controllando il tipo di oggetto utilizzando il metodo "instanceof". Ad esempio, se pageType istanza di Text, abbiamo aggiunto del testo a una pagina. Ma questo metodo non è sostenibile perché se hai bisogno di un nuovo tipo di contenuto, devi aggiungere se condizione e corpo per questo tipo. Ecco perché selezioniamo Visitor Pattern.

Sporchiamoci un po' le mani

Innanzitutto, creiamo un'interfaccia chiamata PowerPointContentVisitor e creiamo una classe concreta PowerPointContentVisitorImpl. Questa classe è responsabile di gestire l'aggiunta di elementi all'operazione della pagina. In questo modo, abbiamo separato le operazioni di aggiunta degli articoli ed è diventato più facile da gestire.

public interface PowerPointContentVisitor {
    void visit(POIText poiText);
    void visit(POIImage poiImage);
    void visit(POITable poiTable);
}
@Service
@Slf4j
public class PowerPointContentVisitorImpl implements PowerPointContentVisitor{
    @Override
    public void visit(POIText poiText) {
        log.info("Operations for text");
    }

    @Override
    public void visit(POIImage poiImage) {
        log.info("Operations for image");
    }

    @Override
    public void visit(POITable poiTable) {
        log.info("Operations for table");
    }
}

import com.fasterxml.jackson.annotation.JsonSubTypes;
import com.fasterxml.jackson.annotation.JsonSubTypes.Type;
import com.fasterxml.jackson.annotation.JsonTypeInfo;
import lombok.Data;

@JsonTypeInfo(
        use = JsonTypeInfo.Id.NAME,
        property = "type"
)
@JsonSubTypes({
        @Type(value = POIText.class, name = "text"),
        @Type(value = POIImage.class, name = "image"),
        @Type(value = POITable.class, name = "table"),
})
@Data
public abstract class POIPage {
    private String title;
    abstract void accept(PowerPointContentVisitor powerPointContentVisitor);
}

public class POIText extends POIPage{
    @Override
    void accept(PowerPointContentVisitor powerPointContentVisitor) {
        powerPointContentVisitor.visit(this);
    }
}
public class POIImage extends POIPage {
    @Override
    void accept(PowerPointContentVisitor powerPointContentVisitor) {
        powerPointContentVisitor.visit(this);
    }
}
public class POITable extends POIPage{
    @Override
    void accept(PowerPointContentVisitor powerPointContentVisitor) {
        powerPointContentVisitor.visit(this);
    }
}

@RestController
@RequiredArgsConstructor
public class PageController {

    private final PowerPointContentVisitor powerPointContentVisitor;

    @PostMapping("/pptx/pages/")
    public void addPage(@RequestBody List<POIPage> poiPages) {
        poiPages.forEach(poiPage -> poiPage.accept(powerPointContentVisitor));
    }
}

[
    {
     "title": "Text Page",
     "type": "text"
    },
    {
     "title": "Image Page",
     "type": "image"
    },
    {
     "title": "Table Page",
     "type": "table"
    }
]

risultato