2010-10-14 10 views
6

Me preguntaba cómo se pueden ocultar condicionalmente los datos en clase. Por ejemplo, digamos que tengo una clase llamada Car que tiene tres campos: Engine, MeterReading y Mileage.Cómo implementar la encapsulación condicional en C#

Tengo otras tres entidades llamadas: Conductor, mecánico y pasajero. Ahora lo que quiero es que:

Un conductor sólo debe ser capaz de acceder a Kilometraje (y no del motor y MeterReading)

un mecánico sólo debe ser capaz de acceder a motor y cambio de kilometraje (y no MeterReading)

Un pasajero sólo debe ser capaz de acceder MeterReading (y no del motor y cambio de kilometraje)

Cuál podría ser la mejor manera de poner en práctica esta .. (sin basar toda la lógica en si else)?

¿Alguna idea, chicos?

Gracias.

Respuesta

4

Yo usaría explicit interface implementation. Oculta la implementación de la interfaz cuando se accede a un objeto por su tipo. La implementación solo es accesible cuando se accede por interfaz. En su ejemplo:

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

Por supuesto, debe señalarse que esto solo protege contra accidentes durante la codificación, pero no es una medida de seguridad contra clientes hostiles porque el código del cliente todavía puede convertir una instancia de 'IUsableByPassenger' a' Car' y luego a 'IUsableByMechanic' y todos los demás – Timwi

+0

Claro, pero no hay forma de evitar eso al exponer cualquier objeto capaz de hacer algo más que expuesto. Siempre se puede usar la reflexión para encontrar un tipo, leer partes privadas, etc. – NOtherDev

+0

@A: es posible evitar que el código de cliente que no es de confianza use la reflexión, pero no para evitar la conversión simple. – Timwi

12

La primera idea que me vino a la mente es que tu clase Car implemente 3 interfaces diferentes que cada clase puede usar para interactuar con tu clase Car.

Por ejemplo, (y mis nombres sin duda puede ser mejorado, pero se debe tener la idea), la interfaz IDriverAccess podría ser la siguiente:

public interface IDriverAccess 
{ 
    double Mileage { get; } 
} 

La interfaz IMechanicAccess podría ser la siguiente:

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

    double Mileage { get; } 
} 

Y así sucesivamente. Su clase de automóvil puede implementar estas interfaces, pero las clases para el conductor, el mecánico, el pasajero & solo usarán las interfaces para interactuar con el objeto.

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

¡Me pegaste a tiempo! – Aliostad

+3

Por supuesto, debe señalarse que esto solo protege contra accidentes durante la codificación, pero no es una medida de seguridad contra clientes hostiles porque el código del cliente todavía puede convertir una instancia de 'IDriverAccess' en' Car' y acceder a todo. – Timwi

+1

Pero cuando implemente esas interfaces implícitamente, la clase 'Car' fuera de' Mechanic' o 'Driver' (es decir, cuando se accede por desagradable' Thief') todavía expondrá todo. – NOtherDev

2

me gustaría crear estas 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; } 
    } 
} 

Y que cada persona utilice la interfaz para acceder al coche.

+0

Como se indicó anteriormente, cuando implemente esas interfaces implícitamente, la clase 'Car' fuera de' Mechanic' o 'Driver' (es decir, cuando se accede por' ladrón' desagradable) todavía expondrá todo. – NOtherDev

+0

Pero no deberían tener acceso y esa es la clave. – Aliostad

+0

Por supuesto, debe señalarse que esto solo protege contra accidentes durante la codificación, pero no es una medida de seguridad contra clientes hostiles porque el código del cliente aún puede convertir una instancia de 'IDrivableCar' en' Car' y acceder a todo. – Timwi

2

haga que la clase implemente las interfaces IEngine, ImaterReading y demás. Proporcione a cada entidad solo el acceso a la interfaz especificada. dicen que un disco tiene acceso IMilage solamente, un IMilage mecánico e IEngine.

+0

¿por qué downvoted this? – Arseny

+0

Lo siento ... ¡eso fue accidental! – Sennin