tags:

views:

117

answers:

3

Hello,

imagine I have two classes A and B where B has the properties BProperty1 and BProperty2.

  • The property BProperty1 shall only be settable by class A (no matter which instance)
  • The property BProperty2 shall only be settable by a concrete instance of class A (the reference to this instance could e.g. be stored on BProperty1).

Is it possible to realize something like that, is there maybe a pattern for it? Please note that A and B are independent, none of them derives from the other one! I'm using C# and WPF. Thanks for any hint!

EDIT An example:

Imagine a class Car and a class CarDoor. Whenever a CarDoor is added to a Car, the CarDoors property AssociatedCar is set to the Car it's assigned to, because this reference is needed later. But how to make sure the AssociatedCar property is not set by the user, but by the Car class when AddCarDoor(door) is called?

class Car
{
    private List<CarDoor> _carDoors = new List<CarDoor>();

    public Car()
    {

    }

    public void AddCarDoor(CarDoor door)
    {
        // Add the door to the car
        _carDoors.Add(door);

        // Save a reference to the car assigned to the door
        door.AssociatedCar = this;
    }
}


class CarDoor
{
    public Car AssociatedCar;

    public CarDoor()
    {

    }
}
A: 

If it is a property, you may want to use System.Diagnostics.StackTrace class) inside the property setter. You just need to check the assembly and the class which called the setter, and throw an exception if it is a class other than the class A.

Notes:

  • Be aware of performance issues.
  • I'm pretty sure that somebody will say that if you need to do this sort of things, it means that there is a flaw in your object-oriented approach. At least, I used this once, and I completely agree that my approach was wrong.
MainMa
I think you mean StackTrace, but I wouldn't recommend this (it's very brittle if you make changes later.)
Dan Bryant
@Dan Bryant: thanks, yes, I meant StackTrace class. And yes, it's brittle, unless you use reflection, which will have a performance cost.
MainMa
+1  A: 

You could lock the setter, then make the object required to unlock it private to class A.

Edit: After seeing your edit, I would suggest that you make a car door a member of class car, seeing as how a car is composed of some x doors. Or perhaps a collection of car doors. Make that member variable private. Then nothing outside of the car class will be able to edit that property of the car door.

Edit2: Also, having a two way association between car and car door (i.e. car door has an associated car, and car has associated car doors) is a bit redundant. I do not see why you would need it - simply set a public get property for the car door, so that you can use that data outside of the car class.

Example...

Class Car
{
    private List<CarDoor> carDoors;

    Car()
    {
         this.carDoors = new List<CarDoor>();
    }

    public List<CarDoor> getCarDoors
    {
         return this.carDoors;
    }
}
badpanda
Thanks for your reply, but I don't understand. Could you maybe add a sample for this? Thaks!
stefan.at.wpf
+1  A: 

Here's one design that shifts responsibilities slightly to create the two-way dependency:

class CarFactory
{
    public Car BuildCar()
    {
        return new Car(BuildDoor);
    }

    public CarDoor BuildDoor(Car car)
    {
        return new CarDoor(car);
    }
}

class Car
{
    private List<CarDoor> _carDoors = new List<CarDoor>();

    public Car(Func<Car, CarDoor> buildDoor)
    {
        for (int i=0; i<4; i++)
            _carDoors.Add(buildDoor(this));
    }
}


class CarDoor
{
    private Car _associatedCar;

    public CarDoor(Car associatedCar)
    {
        _associatedCar = associatedCar;
    }
}

Note, however, that this sort of two-way dependency is a sign of other problems. It could be that CarDoor is doing things that it shouldn't be responsible for doing. Perhaps Car should be doing these things or perhaps you've included responsibilities that really belong in another class entirely, like Mechanic.

Dan Bryant