Vedo un codice come questo nella nostra base di codice e voglio refactoring:
(segue il typescript psuedocode):
class EntityManager{
private findEntityForServerObject(entityType:string, serverObject:any):IEntity {
var existingEntity:IEntity = null;
switch(entityType) {
case Types.UserSetting:
existingEntity = this.getUserSettingByUserIdAndSettingName(serverObject.user_id, serverObject.setting_name);
break;
case Types.Bar:
existingEntity = this.getBarByUserIdAndId(serverObject.user_id, serverObject.id);
break;
//Lots more case statements here...
}
return existingEntity;
}
}
I lati negativi del tipo di accensione sono auto-esplicativi. Normalmente, quando si cambia comportamento in base al tipo, cerco di spingere il comportamento in sottoclassi in modo da poterlo ridurre a una singola chiamata di metodo e lasciare che il polimorfismo si occupi del resto.
Tuttavia, le seguenti due cose mi stanno facendo fermare:
1) Non voglio accoppiare il serverObject con la classe che sta memorizzando tutti questi oggetti. Non sa dove cercare le entità di un certo tipo. E sfortunatamente, l'identità di un tipo di ServerObject varia a seconda del tipo di ServerObject. (Quindi a volte è solo un ID, altre volte è una combinazione di un ID e una stringa identificativa univoca, ecc.). E questo comportamento non appartiene laggiù a quelle sottoclassi. È responsabilità di EntityManager e dei suoi delegati.
2) In questo caso, non posso modificare le classi ServerObject poiché sono semplici oggetti di dati vecchi. Va detto che ho altre istanze del metodo sopra che prendono un parametro come "IEntity" e procedono a fare quasi la stessa cosa (ma modificano leggermente il nome dei metodi che stanno chiamando per ottenere l'identità del entità). Quindi, potremmo avere:
case Types.Bar:
existingEntity = this.getBarByUserIdAndId(entity.getUserId(), entity.getId());
break;
Quindi in questo caso, posso cambiare l'interfaccia dell'entità e le sottoclassi, ma questo non è un comportamento che appartiene a quella classe.
Quindi, penso che mi indica una specie di mappa. Quindi alla fine chiamerò:
private findEntityForServerObject(entityType:string, serverObject:any):IEntity {
return aMapOfSomeSort[entityType].findByServerObject(serverObject);
}
private findEntityForEntity(someEntity:IEntity):IEntity {
return aMapOfSomeSort[someEntity.entityType].findByEntity(someEntity);
}
Il che significa che ho bisogno di registrare una sorta di classi / funzioni di strategia in fase di esecuzione con questa mappa. E ancora, mi raccomando bene ricordati di registrarne uno per ciascun mio tipo, o otterrò un'eccezione di runtime.
C'è un modo migliore per refactoring questo? Mi sento come se mi mancasse qualcosa di veramente ovvio qui.