Come si restringono classi specifiche per una proprietà?

3

Qual è la procedura migliore per specificare quali classi possono essere archiviate in una proprietà di classe? Per esempio se avessi un DTO con un

  • proprietà che dovrebbe consentire ClassA, ClassB, ClassC,
  • un'altra proprietà che consente ClassC, ClassD, ClassE,
  • un'altra proprietà che consente ClassA, ClassC, ClassE,

come dovrei definire queste classi?

Ad esempio,

public class MyDto
{
    public Vehicle Vehicle { get; set; }
    public Machine Machine { get; set; }
}

[Vehicle]
[Machine]
public class Car { }

[Vehicle]
[Machine]
public class Plane { }

[Machine]
public class Robot { }

Aggiorna

Se possibile vorrei evitare di utilizzare interfacce marcatore poiché ciò è considerato un odore di codice?

    
posta Ernest 21.02.2017 - 15:42
fonte

3 risposte

3

Definiresti un'interfaccia che è implementata dall'insieme di classi che permetterete, e quindi impostate il tipo di proprietà come tale interfaccia.

Presumibilmente le classi in questione hanno qualche interfaccia in comune. Se non hanno nulla in comune, la vera domanda è perché vuoi archiviare oggetti non correlati nella stessa proprietà.

Le interfacce Marker sono effettivamente considerate un odore di codice, ma un odore di codice è (secondo wikipedia):

any symptom in the source code of a program that possibly indicates a deeper problem

Quindi l'interfaccia marker non è il problema che devi risolvere. Piuttosto, indicano che hai un problema più profondo, che è indicato dalla necessità di memorizzare oggetti non correlati nello stesso slot.

    
risposta data 21.02.2017 - 16:10
fonte
0

Ci possono essere un paio di approcci a questo.

È possibile creare interfacce create per tipo Macchina e Veicolo e avere di conseguenza tipi di proprietà nella classe MyDto.

public interface IMachine
{
    //properties and methods related to Machine
}

public interface IVehicle : IMachine
{
    //properties and methods specific to Vehicle.
}

public class Car : IVehicle
{
    // Implementation of all the members of IMachine and IVehicle
}

public class Plane : IVehicle
{
    // Implementation of all the members of IMachine and IVehicle
}

public class Robot : IMachine
{
    // Implementation of all the members of IMachine
}

public class MyDto
{
    public IVehicle Vehicle {get;set;}
    public IMachine Machine {get;set;}
}

In questo modo Vehicle proprietà di MyDto accetterà solo oggetto di classi che implementano l'interfaccia IVehicle (significa oggetti di classi Car e Plane ) e la proprietà Machine accetterà accept object of classes interface interface IMachine (significa oggetti delle classi Robot e Car e Plane to as they also implement interface IMachine 'indirettamente).

Un altro approccio potrebbe essere quello di creare la classe di base VehicleBase per l'implementazione dell'interfaccia IVehicle1 di Vehicle e di ereditarla in Car e Plane . E modifica il tipo di proprietà Vehicle in VehicleBase .

public abstract class VehicleBase : IVehicle
{
    // Implement members of IVehicle and IMachine as abstract or virtual
}

public class Car : VehicleBase
{
    // Implement abstract members and override virtual members
}

public class Plane : VehicleBase
{
    // Implement abstract members and override virtual members
}

public class MyDto
{
    public VehicleBase Vehicle {get;set;}
    public IMachine {get;set;}
}
    
risposta data 21.02.2017 - 16:49
fonte
0

Quello che stai cercando è comunemente chiamato tipo di somma .

La tua prima proprietà avrebbe il tipo di somma ClassA + ClassB + ClassC ,  la tua seconda proprietà ClassC + ClassD + ClassE e la tua terza proprietà ClassA + ClassC + ClassE .

es. in Haskell, i tipi sarebbero simili a questo:

data ABC = A ClassA | B ClassB | C ClassC
data CDE = C ClassC | D ClassD | E ClassE
data ACE = A ClassA | C ClassC | E ClassE

E in Rust, i tipi apparirebbero in questo modo:

enum ABC { A(ClassA), B(ClassB), C(ClassC) }
enum CDE { C(ClassC), D(ClassD), E(ClassE) }
enum ACE { A(ClassA), C(ClassC), E(ClassE) }

Swift sarebbe simile:

enum ABC {
  case A(ClassA)
  case B(ClassB)
  case C(ClassC)
}

enum CDE {
  case C(ClassC)
  case D(ClassD)
  case E(ClassE)
}

enum ACE {
  case A(ClassA)
  case C(ClassC)
  case E(ClassE)
}

Scala non supporta nativamente i tipi di somma, ma puoi facilmente emularli usando gerarchie di ereditarietà sigillate:

sealed trait ABC
object ABC {
  final case class A(a: ClassA) extends ABC
  final case class B(b: ClassB) extends ABC
  final case class C(c: ClassC) extends ABC
}

sealed trait CDE
object CDE {
  final case class C(c: ClassC) extends CDE
  final case class D(d: ClassD) extends CDE
  final case class E(e: ClassE) extends CDE
}

sealed trait ACE
object ACE {
  final case class A(a: ClassA) extends ACE
  final case class C(c: ClassC) extends ACE
  final case class E(e: ClassE) extends ACE
}

(Puoi astrarre la lastra usando una macro.)

    
risposta data 22.02.2017 - 17:50
fonte

Leggi altre domande sui tag