2010-10-14 6 views
6

Ich frage mich, wie man Daten in der Klasse bedingt verstecken kann. Zum Beispiel sagen wir, ich habe eine Klasse namens Car, die drei Felder hat: Engine, MeterReading und Kilometerstand.Wie bedingte Kapselung in C implementieren #

Ich habe drei andere Einheiten namens: Fahrer, Mechaniker und Passagier. Nun, was ich will, ist, dass:

Ein Treiber sollte nur in der Lage sein, Kilometerstand zugreifen (und nicht Motor und Meterreading)

Ein Mechaniker sollte nur in der Lage sein, Motor und Kilometerstand zu gelangen (und Meterreading nicht)

Ein Fahrgast sollte nur auf MeterReading zugreifen können (und nicht auf Motor und Kilometer).

Was könnte der beste Weg sein, dies zu implementieren ... (ohne die ganze Logik auf andere Anweisungen zu stützen)?

Irgendwelche Ideen Leute?

Danke.

Antwort

4

Ich würde explicit interface implementation verwenden. Es verbirgt die Implementierung der Schnittstelle, wenn auf den Objekttyp von seinem Typ zugegriffen wird. Die Implementierung ist nur beim Zugriff über die Schnittstelle zugänglich. In Ihrem Beispiel:

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

Natürlich sollte darauf hingewiesen werden, dass dies nur vor Unfällen während der Codierung schützt, aber es ist keine Sicherheitsmaßnahme gegen feindliche Clients, da der Client-Code immer noch eine Instanz von "IUsableByPassenger" auf "Car" und dann auf "IUsableByMechanic" werfen kann und alle anderen. – Timwi

+0

Sicher, aber es gibt keine Möglichkeit, das zu vermeiden, wenn irgendein Objekt in der Lage ist, mehr als nur ausgesetzt zu tun. Man kann immer Reflektion verwenden, um einen Typ zu finden, lesen Sie Privates usw. – NOtherDev

+0

@A: Es ist möglich, nicht vertrauenswürdigen Client-Code von der Verwendung von Reflektion zu verhindern, aber nicht, einfaches Casting zu verhindern. – Timwi

12

Die erste Idee, die in den Sinn kam wäre, Ihre Car Klasse implementieren 3 verschiedene Schnittstellen, die jede andere Klasse verwenden können, um mit Ihrer Car Klasse zu interagieren.

Zum Beispiel (und meine Namen können auf jeden Fall verbessert werden, aber man sollte auf die Idee kommen), die IDriverAccess Schnittstelle könnte wie folgt aussehen:

public interface IDriverAccess 
{ 
    double Mileage { get; } 
} 

Die IMechanicAccess Schnittstelle könnte wie folgt aussehen:

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

    double Mileage { get; } 
} 

Und so weiter. Ihre Fahrzeugklasse kann diese Schnittstellen dann implementieren, aber die Klassen für den Fahrer, Mechaniker, Passagier & werden nur die Schnittstellen verwenden, um mit dem Objekt zu interagieren.

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

Sie schlagen mich rechtzeitig! – Aliostad

+3

Natürlich ist darauf hinzuweisen, dass dies nur vor Unfällen während der Codierung schützt, aber es ist keine Sicherheitsmaßnahme gegen feindliche Clients, da der Client-Code immer noch eine Instanz von "IDriverAccess" in "Car" werfen und auf alles zugreifen kann. – Timwi

+1

Aber wenn Sie diese Interfaces implizit implementieren, werden 'Car'-Klasse außerhalb' Mechanic' oder 'Driver' (d. H. Wenn von bösartigem' Dieb' zugegriffen wird) immer noch alles aussetzen. – NOtherDev

2

Ich würde diese Schnittstellen erstellen:

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

Und jede Person, lassen Sie die Schnittstelle verwenden, um das Auto zu öffnen.

+0

Wie oben - wenn Sie diese Schnittstellen implizit implementieren, wird 'Car'-Klasse außerhalb' Mechanic' oder 'Driver' (d. H. Wenn von einem fiesen' Dieb' zugegriffen wird) immer noch alles enthüllen. – NOtherDev

+0

Aber sie sollten keinen Zugang haben und das ist der Schlüssel. – Aliostad

+0

Natürlich sollte darauf hingewiesen werden, dass dies nur vor Unfällen während der Codierung schützt, aber es ist keine Sicherheitsmaßnahme gegen feindliche Clients, da der Client-Code immer noch eine Instanz von "IDrivableCar" auf "Car" werfen und auf alles zugreifen kann. – Timwi

2

make class Auto implementiert Schnittstellen IEngine, ImaterReading und so. Geben Sie jeder Entität nur den Schnittstellenzugriff an. sagen, ein Laufwerk hat nur IMilage Zugriff, ein Mechaniker IMilage und IEngine.

+0

Warum downvoted dies? – Arseny

+0

Sorry .. das war zufällig! – Sennin