views:

69

answers:

4

Suppose you have this class:

public class A
{
    private int number;
    public setNumber(int n){
        number = n;
    }
}

I'd like the method setNumber could be called only by objects of a specific class. Does it make sense? I know it is not possible, is it? Which are the design alternatives? Some well known design pattern? Sorry for the silly question, but I'm a bit rusty in OO design.

EDIT: I should be more clear. Sorry. I know setNumber can be invoked only by objects of class A. I'd like that only objects of a specific class (having a reference to class A objects), could call

classAObj.setNumber(n);
+1  A: 

Well by making the method a member of the class "A" it can only be called by objects of that class.

So if you had another object of class "B" then it couldn't call setNumber because that method wouldn't exist.

Or have I missed something in your question?

It appears I have.

If you have two other classes "C" and "D" both of which hold a reference to an instance of "A" then that's a different problem.

I can't think of a "nice" way of doing this. The only thing that springs to mind is to have:

public class A
{
    private int number;
    public setNumber(object sender, int n)
    {
        if (sender.GetType() == C) // Not sure of the exact syntax here
        {
            number = n;
        }
    }
}

Then when you call setNumber you'd have:

objectA.setNumber(this, 23);

However, that doesn't stop the writer of the code creating an object of type "C" to pass that into the method:

C objectC = new C();
objectA.SetNumber(objectC, 23);
ChrisF
I think the poster is imagining a scenario where a bunch of different classes have references to instances of class A, but only some of them should be able to call that particular method (depending of the class of the container).
JacobM
Yes, this is the scenario.
mp
@ChrisF in the scenario you're interpreting, I would probably use something like if (new[] { typeof(C), typeof(D) }.Contains(sender.GetType())){ //Do stuff }
BenAlabaster
A: 

Remember that anObject.setNumber makes sense only for objects of class "A"

belisarius
+1  A: 

Let's say you want setNumber to be only called by class AllowedSetNumber. One possible solution is to mandate that you pass an instance of AllowedsetNumber as a parameter, e.g.

public class A
{
    private int number;
    public setNumber(int n, AllowedSetNumber caller){
        number = n;
    }
}

So then the question becomes, how can I stop anyone from creating an AllowedSetNumber instance. This is quite a bit easier to nail down - you can do that with object factories. Making the constructor of AllowedSetNumber package private, or even private with a factory method.

Another alternative, that doesn't require changing the method signature, is to have a thread-local security context in the same vein as the java SecurityManager. This works by analysing stack traces when an object requests permission, and so the calling code can be authenticated, and then authorized according to the security policy.

See java.security.PrivilegedAction<T>

mdma
Another way would be to reference the caller through some mechanism similar to reflection if it is available in the framework being used.
BenAlabaster
A: 

I need some clarification as to what exactly you mean by "specific classes"... but I'm hoping that I'm interpreting correctly in that you only want instances of class A to be able to call the method.

public class A
{
  private int number;
  private void setNumber(int Number)
  {
    number = Number;
  }
}

In this case, any instances of class A can call the method:

A myAinstance = new A();
myAinstance.setNumber(5);

However, you wouldn't be able to refer to A.setNumber() as if it were a static method - without relation to an instance.

If you want only derived classes (from any assembly) to be able to call it:

public class A
{
  private int number;
  protected void setNumber(int Number)
  {
    number = Number;
  }
}

public class B : A
{
}

In this case, any instances of class B or A could call setNumber(), but no other classes could see or access it.

If you only want all instances classes within the same assembly to be able to call it:

public class A
{
  private int number;
  internal void setNumber(int Number)
  {
    number = Number;
  }  
}

In this case, any classes within the same assembly as your class 'A' will be able to call setNumber() as if it were a public property, but no classes contained in other assemblies will be able to see it or reference it. In VB.NET internal is the same as 'Friend'.

If you only want derived classes within the same assembly to be able to call it:

public class A
{
  private int number;
  protected internal void setNumber(int Number)
  {
    number = Number;
  }
}

public class B : A
{
}

In this case, any instances of class B or A regardless of assembly can see and reference setNumber(); and any classes within the same assembly as class A will be able to see it or reference it as if it were public.

I think that covers each of the options...

BenAlabaster