Quando rendere un metodo parte di un'interfaccia o di un'implementazione concreta? [duplicare]

0

Creo un'interfaccia per l'accesso al database in un database MySQL. Attualmente, questo è l'unico modo per accedere al giorno, ma per rendere più facile il test e nel caso in cui l'accesso ai dati potrebbe cambiare, ho usato un'interfaccia.

Tuttavia, ora mi trovo di fronte al dilemma di quali metodi dovrei mettere sull'interfaccia e su quali metodi dovrei applicare concretamente all'implementazione. C'è una regola generale per questo?

Fornirò un esempio qui sotto dove ho alcune operazioni CRUD per un'interfaccia ICar , ma poi alcune altre funzioni di utilità che sono solo sull'implementazione concreta. Dovrebbero essere anch'essi sull'interfaccia? Non vorrei che un utente dovesse implementare ogni metodo se non ne avesse bisogno?

interface ICar {
   Car GetCar(int id);
   void DeleteCar(int id);
   void InsertCar(Car car)
   Car UpdateCar(Car car);
}

class Car : ICar {

  Car GetCar(int id) {}

  void DeleteCar(int id) {}

  void InsertCar(Car car) {}

  Car UpdateCar(Car car) {}

  // methods not on interface, but should they be

  public string GetCarVIN(Car car) {}

  public string GetCarColor(Car car) {}

  public string GetCarMake(Car car) {}

  public string GetCarModel(Car car) {}

  public string GetCarOwner(Car car) {}
}
    
posta xaisoft 27.03.2015 - 04:42
fonte

4 risposte

3

L'OP sta avendo questa confusione a causa della scarsa nomenclatura.

La ragione per cui OP pone questa domanda è perché l'OP ha una confusione tra il schema del repository e la progettazione generale orientata agli oggetti.

L'oggetto repository si trova tra il design OOP, ad esempio una classe Car e il database.

La relazione "repository-object" non deve essere confusa con la relazione "interface-implementation" o con le relazioni "class-object" / "static-instance".

Un oggetto Car fornisce accesso alle proprietà che un'auto (nella vita reale) di solito ha (denominate VIN , Color , Make , Model e Owner nell'esempio di codice) .

Al contrario, l'oggetto repository ha l'aspetto di CarCollection in senso astratto. L'oggetto repository è l'indirizzo a cui appartiene l'operazione CRUD.

Per risolvere questo problema, i metodi CRUD dovrebbero esistere su una classe CarRepository (e facoltativamente implementare un'interfaccia ICarRepository ), quindi i metodi relativi all'auto dovrebbero esistere su un oggetto Car e / o su ICar interfaccia.

In C #, puoi mantenere le interfacce pulite e dare comunque la comodità ai tuoi utenti utilizzando l'estensione metodi .

Tieni presente che se la confusione concettuale dell'oggetto repository con l'oggetto dati è sufficiente per dare mal di testa a OP, gli utenti di tale confusione concettuale avranno lo stesso tipo di mal di testa, a meno che gli utenti non siano preavvertiti riguardo esso.

public interface ICarRepository
{
    ICar GetCar(int carId);

    // ... other CRUD and query methods,
    // ... but NO car-properties here.
}

public interface ICar
{
    string Owner { get; }
    string VIN { get; }

    // ... other car-properties here.
}

namespace ExtensionMethods
{
    public static class CarExtensions
    {
        public static string GetCarOwnerFromId(this ICarRepository carRepo, int carId)
        {
            return carRepo.GetCar(carId).Owner;
        }

        public static string GetCarVINFromId(this ICarRepository carRepo, int carId)
        {
            return carRepo.GetCar(carId).VIN;
        }
    }
}
    
risposta data 28.03.2015 - 22:42
fonte
2

L'interfaccia dovrebbe essere il più generica possibile. Quindi, anche se questa è un'interfaccia di Cars, se supponiamo che qualsiasi auto sarà in grado di avere un proprietario, allora il metodo per ottenere il proprietario dovrebbe essere all'interno dell'interfaccia.

Tuttavia, qualsiasi metodo non generico, ad es. il metodo per prendere il modello della TV dell'auto non dovrebbe essere all'interno dell'interfaccia, poiché non tutte le auto avranno una TV.

Cerca di includere i metodi che ogni automobile può avere all'interno dell'interfaccia. Tutti gli altri metodi che solo alcune macchine possederanno saranno lasciati fuori dall'interfaccia.

    
risposta data 27.03.2015 - 08:26
fonte
0

However, now I am faced with the dilemma of which methods I should put on the interface and which methods I should put on the concrete implementation" directly. Is there a rule of thumb for this?

Dividi la differenza e crea una classe abstract .

    
risposta data 27.03.2015 - 22:04
fonte
0

Se intendi utilizzare l'interfaccia per test più semplici, allora dovrebbe esporre tutta la logica che desideri testare sull'oggetto business di Car. Ciò significa che ogni operazione che riguarda la macchina e non l'implementazione tecnica.

Nel tuo esempio, includerei tutti quei metodi in ICar.

Non escluderei alcuni metodi, anche se solo alcune macchine li hanno. Dovresti inserirli in un'interfaccia separata o utilizzare l'ereditarietà, a seconda della situazione.

    
risposta data 28.03.2015 - 21:10
fonte

Leggi altre domande sui tag