2010-10-14 6 views
6

Je me demandais comment on peut conditionnellement cacher les données en classe. Par exemple, disons que j'ai une classe appelée Car qui a trois champs: Engine, MeterReading et Mileage.Comment implémenter l'encapsulation conditionnelle en C#

J'ai trois autres entités appelées: Driver, Mechanic et Passenger. Maintenant, ce que je veux est que:

Un pilote ne devrait être en mesure d'accéder Mileage (et non du moteur et MeterReading)

Un mécanicien ne doit pouvoir accéder à moteur et le kilométrage (et non MeterReading)

Un passager devrait seulement pouvoir accéder à MeterReading (et non au moteur et au kilométrage)

Quelle pourrait être la meilleure manière d'implémenter ceci .. (sans baser toute la logique dessus si d'autres instructions)?

Des idées les gars?

Merci.

Répondre

4

Je voudrais utiliser explicit interface implementation. Il cache l'implémentation de l'interface lorsque l'objet est accédé par son type. L'implémentation est accessible uniquement lors de l'accès par interface. Dans votre exemple:

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

Bien sûr, cela ne fait que prévenir les accidents lors du codage, mais ce n'est pas une mesure de sécurité contre les clients hostiles parce que le code client peut encore convertir une instance de 'IUsableByPassenger' en' Car' et ensuite 'IUsableByMechanic' et tous les autres. – Timwi

+0

Bien sûr, mais il n'y a aucun moyen d'éviter cela lors de l'exposition de tout objet capable de faire plus qu'exposé. On peut toujours utiliser la réflexion pour trouver un type, lire des fichiers privés, etc. – NOtherDev

+0

@A: Il est possible d'empêcher le code client non sécurisé d'utiliser la réflexion, mais pas d'empêcher le simple casting. – Timwi

12

La première idée qui est venue à l'esprit serait que votre classe Car implémente 3 interfaces différentes que chaque autre classe peut utiliser pour interagir avec votre classe Car.

Par exemple, (et mes noms peuvent certainement être améliorés, mais vous devriez avoir l'idée), le pourrait être aussi l'interface IDriverAccess suit:

public interface IDriverAccess 
{ 
    double Mileage { get; } 
} 

L'interface IMechanicAccess pourrait être la suivante:

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

    double Mileage { get; } 
} 

Et ainsi de suite. Votre classe de voiture peut ensuite mettre en œuvre ces interfaces, mais les classes pour le conducteur, le mécanicien, & passager utiliseront simplement les interfaces pour interagir avec l'objet.

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

Tu m'as battu à l'heure! – Aliostad

+3

Bien sûr, il convient de noter que cela ne protège que des accidents pendant le codage, mais ce n'est pas une mesure de sécurité contre les clients hostiles parce que le code client peut toujours lancer une instance de 'IDriverAccess'' Car' et accéder à tout. – Timwi

+1

Mais lorsque vous implémentez implicitement ces interfaces, la classe 'Car' en dehors de' Mechanic' ou 'Driver' (c'est-à-dire quand elle est accédée par un méchant' Thief') continuera à tout exposer. – NOtherDev

2

Je voudrais créer ces interfaces:

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; } 
    } 
} 

Et que chaque personne utilise l'interface pour accéder à la voiture.

+0

Comme ci-dessus - lorsque vous implémentez implicitement ces interfaces, la classe 'Car' en dehors de' Mechanic' ou 'Driver' (c'est-à-dire quand elle est accédée par un méchant' Thief') continuera à tout exposer. – NOtherDev

+0

Mais ils ne devraient pas y avoir accès et c'est la clé. – Aliostad

+0

Bien sûr, il convient de noter que cela ne protège que des accidents pendant le codage, mais ce n'est pas une mesure de sécurité contre les clients hostiles, car le code client peut toujours convertir une instance de 'IDrivableCar' en' Car' et accéder à tout. – Timwi

2

faire classe Car implémenté les interfaces IEngine, ImaterReading et ainsi de suite. Donnez à chaque entité uniquement l'accès à l'interface spécifc. dire un lecteur a obtenu l'accès IMilage seulement, un mécanicien IMilage et IEngine.

+0

pourquoi downvoted ceci? – Arseny

+0

Désolé ... c'était accidentel! – Sennin

Questions connexes