views:

117

answers:

4

I was wondering how one can conditionally hide data in class. For instance , lets say I have a class called Car which has three fields : Engine , MeterReading and Mileage.

I have three other entities called : Driver , Mechanic and Passenger. Now what I want is that :

A Driver should only be able to access Mileage ( and not Engine and MeterReading)

A Mechanic should only be able to access Engine and Mileage( and not MeterReading)

A Passenger should only be able to access MeterReading ( and not Engine and Mileage )

What could be the best way to implement this ..( without basing the whole logic on if else statements ) ?

Any ideas guys ?

Thanks.

+11  A: 

The first idea that came to mind would be to have your Car class implement 3 different interfaces which each other class can use to interact with your Car class.

For example, (and my names can definitely be improved upon, but you should get the idea), the IDriverAccess interface could be as follows:

public interface IDriverAccess
{
  double Mileage { get; }
}

The IMechanicAccess interface could be as follows:

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

  double Mileage { get; }
}

And so on. Your car class can then implement these interfaces, but the classes for the driver, mechanic, & passenger will just use the interfaces to interact with the object.

public Car : IDriverAccess, IMechanicAccess, IPassengerAccess
{
  // implement the interfaces
}
Eric
You beat me on time!
Aliostad
Of course it should be pointed out that this only guards against accidents while coding, but it is not a security measure against hostile clients because the client code can still cast an instance of `IDriverAccess` to `Car` and access everything.
Timwi
But when you implement that interfaces implicitly, `Car` class outside `Mechanic` or `Driver` (i.e. when accessed by nasty `Thief`) will still expose everything.
A.
@Timewi and @A, if this a real concern, you can make the Car an internal class and only ever expose it as various interfaces. Of course, the Thief could still force-cast between interfaces or even use Reflection to break in. You can prevent force-casting by implementing the different interfaces with sub-classes (this can be a good use case for private nested classes), but there's not much you can do about Reflection besides running with partial trust.
Dan Bryant
+2  A: 

I would create these 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; }
    }
}

And let each person use the interface to access the car.

Aliostad
As above - when you implement that interfaces implicitly, `Car` class outside `Mechanic` or `Driver` (i.e. when accessed by nasty `Thief`) will still expose everything.
A.
But they should not have access to it and that is the key.
Aliostad
Of course it should be pointed out that this only guards against accidents while coding, but it is not a security measure against hostile clients because the client code can still cast an instance of `IDrivableCar` to `Car` and access everything.
Timwi
+2  A: 

I would use explicit interface implementation. It hides implementation of interface when object is accessed by its type. The implementation is accessible only when accessing by interface. In your example:

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
    }
}
A.
Of course it should be pointed out that this only guards against accidents while coding, but it is not a security measure against hostile clients because the client code can still cast an instance of `IUsableByPassenger` to `Car` and then to `IUsableByMechanic` and all the others.
Timwi
Sure, but there is no way to avoid that when exposing any object capable somehow of doing more than exposed. One can always use reflection to find a type, read privates etc.
A.
@A: It is possible to prevent untrusted client code from using reflection, but not to prevent simple casting.
Timwi
Thanks a lot guys for all your answers .. the "explicit interface implementation" is what I was looking for .
Sennin
And apologies for any confusion (accidental down-voting) that I might have caused ..( I'm kinda new to this :) )
Sennin
+2  A: 

make class Car implemented interfaces IEngine,ImaterReading and so. Give each entity only specifyc interface access. say a drive got IMilage access only, a mechanic IMilage and IEngine.

Arseny
why downvoted this?
Arseny
@Arseny : Sorry .. that was accidental !
Sennin