Scenario:
Ho una situazione in cui devo refactoring un servizio Web con un singolo endpoint API che utilizza logica complessa per inserire, aggiornare e recuperare i dati da un database. I client usano una chiamata e, a seconda dell'oggetto di trasferimento dati che inviano, il servizio sta facendo cose diverse (l'API non è stata progettata da me quindi non posso farci nulla: deve supportare i client esistenti).
Quindi, ad esempio, un client invia il seguente JSON:
{
"Id": 1234,
"FacebookToken": "some facebook access token"
}
Quindi il servizio deve rispondere con i dati recuperati dal database. Tutti i campi nella richiesta JSON sono opzionali e, a seconda del tipo di combinazione di essi hanno valori o meno, e sul contenuto corrente del database, il servizio deve creare, aggiornare o non modificare un'entità nel database, e restituire l'entità creata / aggiornata / selezionata al client.
Domanda
La mia domanda è se riesci a pensare a schemi di progettazione che potrei usare per evitare di implementare la logica come una serie di istruzioni% co_de nidificate nel livello dominio. Non sto parlando di dividerlo in funzioni a grana fine (ho già questo), ma di più su come coinvolgere l'orientamento degli oggetti e il polimorfismo nel design, magari utilizzare alcuni modelli di design ben noti.
Mi rendo conto che non c'è una risposta a questo, ma mi chiedo solo se qualcuno ha affrontato problemi di progettazione simili e ha qualche buon suggerimento. Grazie in anticipo.
Esempio di soluzione non valida:
Ecco un semplice esempio in C # di come non desideri implementare il servizio. Si noti che è intenzionalmente semplicistico mantenerlo breve, normalmente avrei interfacce e usato il contenitore di iniezione delle dipendenze, ecc. La parte più rilevante per la domanda qui è il metodo Service.PostRequest ().
public class Request
{
public string Id { get; set; }
public string ExternalServiceToken { get; set; }
}
public class Response
{
public string Id { get; set; }
public string Name { get; set; }
public override string ToString()
{
return $"{Id}: {Name}";
}
}
public class UserEntity
{
public string Id { get; set; }
public string Name { get; set; }
}
public class Service
{
private readonly Repository _repository;
private readonly ExternalService _externalService;
public Service(Repository repository, ExternalService externalService)
{
_repository = repository;
_externalService = externalService;
}
public Response PostRequest(Request request)
{
if (request == null) // create new entity
{
return ResponseFactoryMethod(_repository.Create(null));
}
UserEntity entity;
if (request.Id != null) // requested specific entity
{
entity = _repository.SelectById(request.Id);
if (request.ExternalServiceToken != null && entity.Name == null) // update entity with Name
{
entity.Name = _externalService.GetName(request.ExternalServiceToken);
_repository.AssignName(entity.Id, entity.Name);
}
return ResponseFactoryMethod(entity);
}
// entity.Id == null
if (request.ExternalServiceToken != null)
{
string name = _externalService.GetName(request.ExternalServiceToken);
entity = _repository.SelectByName(name); // try to find entity by Name, otherwise create
if (entity == null)
{
entity = _repository.Create(name);
}
return ResponseFactoryMethod(entity);
}
return ResponseFactoryMethod(_repository.Create(null));
}
private Response ResponseFactoryMethod(UserEntity entity)
{
var response = new Response();
response.Id = entity.Id;
response.Name = entity.Name;
return response;
}
}
public class ExternalService
{
private Dictionary<string, string> _names = new Dictionary<string, string>
{
{ "abc", "John" },
{ "def", "Jane" },
{ "ghi", "Bob" }
};
public string GetName(string token)
{
return _names[token];
}
}
public class Repository
{
private readonly List<UserEntity> _entities = new List<UserEntity>();
public UserEntity Create(string name)
{
var newUser = new UserEntity { Id = _entities.Count.ToString(), Name = name };
_entities.Add(newUser);
return newUser;
}
public UserEntity SelectById(string id)
{
return _entities.SingleOrDefault(e => e.Id == id);
}
public UserEntity SelectByName(string name)
{
return _entities.SingleOrDefault(e => e.Name == name);
}
public void AssignName(string id, string name)
{
UserEntity user = SelectById(id);
if (user != null)
{
user.Name = name;
}
}
}
public class Client
{
private static Service _service;
public static void Main(string[] args)
{
var repository = new Repository();
_service = new Service(repository, new ExternalService());
RequestFromService(null);
RequestFromService(new Request {Id = "0", ExternalServiceToken = "abc"});
RequestFromService(new Request());
RequestFromService(new Request { Id = "1", ExternalServiceToken = "def" });
RequestFromService(new Request {ExternalServiceToken = "ghi"});
RequestFromService(new Request {ExternalServiceToken = "ghi" });
Console.ReadLine();
}
static void RequestFromService(Request request)
{
Response response = _service.PostRequest(request);
string responseAsString = response != null ? response.ToString() : "null";
Console.WriteLine("Response from service: " + responseAsString);
}
}