2010-10-14 16 views
6

Mi chiedevo come si possano nascondere in modo condizionale i dati in classe. Ad esempio, diciamo che ho una classe chiamata Car che ha tre campi: Engine, MeterReading e Chilometraggio.Come implementare l'incapsulamento condizionale in C#

Ho tre altre entità chiamate: Driver, Mechanic e Passenger. Ora quello che voglio è che:

un driver deve solo essere in grado di accedere a distanza in miglia (e non del motore e MeterReading)

Un meccanico deve solo essere in grado di accedere a motore e il chilometraggio (e non MeterReading)

Un Passeggero dovrebbe essere in grado di accedere a MeterReading (e non a Motore e Chilometraggio)

Quale potrebbe essere il modo migliore per implementare questo .. (senza basare l'intera logica su if else statements)?

Qualche idea ragazzi?

Grazie.

risposta

4

Vorrei utilizzare explicit interface implementation. Nasconde l'implementazione dell'interfaccia quando si accede all'oggetto dal suo tipo. L'implementazione è accessibile solo quando si accede tramite interfaccia. Nel tuo esempio:

interface IUsableByPassenger 
{ 
    MeterReading MeterReading 
    { 
     get; set; 
    } 
} 

interface IUsableByDriver 
{ 
    Mileage Mileage 
    { 
     get; set; 
    } 
} 

interface IUsableByMechanic : IUsableByDriver 
{ 
    Engine Engine 
    { 
     get; set; 
    } 
} 

class Car : IUsableByMechanic, IUsableByPassenger 
{ 
    Mileage IUsableByDriver.Mileage 
    { 
     // implement mileage access 
    } 

    Engine IUsableByMechanic.Engine 
    { 
     // implement engine access 
    } 

    MeterReading IUsableByPassenger.MeterReading 
    { 
     // implement engine access 
    } 
} 

class Mechanic 
{ 
    public Mechanic(IUsableByMechanic usable) 
    { 
     // usable.MeterReading is not here 
    } 
} 
+0

Ovviamente si deve sottolineare che questo solo protegge da incidenti durante la codifica, ma non è una misura di sicurezza contro client ostili perché il codice client può ancora trasmettere un'istanza di 'IUsableByPassenger' a' Car' e quindi a 'IUsableByMechanic' e tutti gli altri. – Timwi

+0

Certo, ma non c'è modo di evitarlo quando si espone un oggetto in qualche modo capace di fare qualcosa di più che esposto. Si può sempre usare la riflessione per trovare un tipo, leggere i dati personali ecc. – NOtherDev

+0

@A: È possibile impedire che il codice client non fidato utilizzi il reflection, ma non per impedire il cast semplice. – Timwi

12

La prima idea che mi viene in mente sarebbe quella di avere la tua classe Car implementare 3 interfacce diverse che ogni altra classe può utilizzare per interagire con la tua classe Car.

Per esempio, (e le mie nomi possono sicuramente essere migliorate, ma si dovrebbe ottenere l'idea), l'interfaccia IDriverAccess potrebbe essere la seguente:

public interface IDriverAccess 
{ 
    double Mileage { get; } 
} 

L'interfaccia IMechanicAccess potrebbe essere la seguente:

public interface IMechanicAccess 
{ 
    EngineObject Engine { get; set; } 

    double Mileage { get; } 
} 

E così via. La classe dell'auto può quindi implementare queste interfacce, ma le classi per il guidatore, il meccanico, il passeggero & useranno semplicemente le interfacce per interagire con l'oggetto.

public Car : IDriverAccess, IMechanicAccess, IPassengerAccess 
{ 
    // implement the interfaces 
} 
+0

Mi hai battuto in tempo! – Aliostad

+3

Ovviamente si deve sottolineare che questo solo protegge da incidenti durante la codifica, ma non è una misura di sicurezza contro client ostili perché il codice client può ancora lanciare un'istanza di 'IDriverAccess' su' Car' e accedere a tutto. – Timwi

+1

Ma quando si implementano implicitamente tali interfacce, la classe 'Car' al di fuori di' Mechanic' o 'Driver' (cioè quando si accede da Nasty' Thief') esporrà ancora tutto. – NOtherDev

2

vorrei creare queste interfacce:

public interface IDriviableCar 
{ 
    object Mileage { get; } 
} 

public interface IRepairableCar 
{ 
    object Engine { get; } 
} 

public interface IHirableCar 
{ 
    object MeterReader { get; } 
} 

public class Car : IDriviableCar, IRepairableCar, IHirableCar 
{ 
    private object _mileage; 

    private object _engine; 

    private object _meterReader; 

    public object Mileage 
    { 
     get { return _mileage; } 
    } 

    public object Engine 
    { 
     get { return _engine; } 
    } 

    public object MeterReader 
    { 
     get { return _meterReader; } 
    } 
} 

E lasciare che ogni persona che usa l'interfaccia per accedere alla macchina.

+0

Come sopra, quando si implementano implicitamente tali interfacce, la classe 'Car' all'esterno di' Mechanic' o 'Driver' (ad esempio quando si accede a Nasty' Thief') esporrà ancora tutto. – NOtherDev

+0

Ma non dovrebbero avere accesso ad esso e questa è la chiave. – Aliostad

+0

Ovviamente va sottolineato che questo protegge solo dagli incidenti durante la codifica, ma non è una misura di sicurezza contro i client ostili perché il codice client può ancora lanciare un'istanza di 'IDrivableCar' su' Car' e accedere a tutto. – Timwi

2

make class Auto implementato interfacce IEngine, ImaterReading e così via. Assegna a ciascuna entità solo l'accesso all'interfaccia specificc. dire che un disco ha accesso solo IMilage, un meccanico IMilage e IEngine.

+0

perché downvoted questo? – Arseny

+0

Scusami .. è stato un caso! – Sennin