PDA

View Full Version : Hiding methods that shouldn't be call-able.



chronozphere
21-01-2011, 11:17 AM
Hey guys,

I have a question for you.

Lets say you've made program containing to modules A and B. There is an object of type X that is known in both modules. X has 4 methods:

> P and Q that should only be called from the code inside module A.
> R and S that should only be called from the code inside module B.

How would you fix this? Just make all methods public and write proper documentation on how to use them, or make a strict separation by using interfaces or something else?

I feel that creating a strict separation makes my program overly complex, while just making everything public feels dirty.

Any ideas?

Thanks

JSoftware
21-01-2011, 11:28 AM
I think the sane thing to do would be to make both public. Always try to make your code as secure as possible, but making sure some procedures only can be called in certain units would be bad design

Can't you place the superclass in module A and derive another class in module B? That was P and Q can be protected, and R+S can be protected in module B?

chronozphere
21-01-2011, 11:43 AM
The downside of your inheritance approach is that both private/protected methods can only be used in one unit. Depending on how our X object is used, this can mean that the entire module A must be defined in one unit. I really prefer to split large modules in multiple units, each having 1-5 classes. I not too keen on this "unit scope" thing that pascal has. ???

Personally, I think other languages do a better job at this. C++ has "friend classes" (though they can be messy). Java has packages. These give you a lot more accessibility control for your classes.

User137
21-01-2011, 01:21 PM
Isn't C++'s "#include" almost equivalent to Pascal call "uses"? But that talk goes about namespaces...

You have another option, module C from wich module A and B are used and controlled together.

virtual
21-01-2011, 05:54 PM
C++ has "friend classes" (though they can be messy). Java has packages
The equivalent in Delphi is to declare package or friend classes in the same unit, which gives them access to the private and protected parts of every class defined in the same unit.

from : Delphi in a Nutshell

Mirage
21-01-2011, 07:20 PM
The both answers in the poll are wrong. First is impossible, second is too bad.
You obviously can't hide parts of public interface depending on interface requester regardless of programming language. How you can do it with C++ or Java?
But you can easily have several interfaces of object X suitable for each module.
Example implementation:


unit xxx; // ;)
interface
type
IXForA = interface
procedure P();
procedure Q();
end;

IXForB = interface
procedure R();
procedure S();
end;

function GetXForA(): IXForA;
function GetXForB(): IXForB;

implementation

type
TX = class(IXForA, IXForB)
...
procedure P();
procedure Q();
procedure R();
procedure S();
end;

function GetXForA(): IXForA;
begin
Result := TX.Create();
end;

function GetXForB(): IXForB;
begin
Result := TX.Create();
end;


This way it will hard to use both interfaces at the same time.

Also you can make private (or protected) all the 4 methods and place the functions GetXForA()/GetXForB() as public ones into class X.

Aggregated classes can be used instead of interfaces for better performance.

Aggregating classes is another approach.:)

chronozphere
21-01-2011, 11:13 PM
Thanks for the many replies. :)

I mentioned Java because in java it is possible to expose methods/variables ONLY to the other classes in the package. In pascal this is possible too, with the restriction that all those classes must be defined within a single unit. It's that last requirement that I don't like. Would be nicer to bundle multiple units into packages and add some kind of "package wide private" access modifier. :)

It's tempting for me to use interfaces, but as I'm using inheritance aswell, things get really complex. Imagine that there are classes Y and Z that are derived from X, each having extra methods that should only be called from either A or B. It means that I have to build multiple interface hierarchies. In the end, it just makes things really really complex, only for the sake of keeping some methods hidden.

There are a lot of options for me. I could also use one interface (with it's own inheritance hierarchy) to connect X with module B, and let module A just access X's public methods. :P

@Mirage: Can you show me an example of aggregation? I've heard that word often, but I don't really know how it solves my problem. Thanks! :)

Mirage
22-01-2011, 03:16 PM
in java it is possible to expose methods/variables ONLY to the other classes in the package. In pascal this is possible too, with the restriction that all those classes must be defined within a single unit. It's that last requirement that I don't like. Would be nicer to bundle multiple units into packages and add some kind of "package wide private" access modifier. :)

In pascal it is possible to expose methods/variables ONLY to the other classes in the unit. In java this is possible too, with the restriction that all those classes must be defined within a single package. It's that last requirement that I don't like. Would be nicer to bundle multiple packages into units and add some kind of "unit wide private" access modifier. ;)



It's tempting for me to use interfaces, but as I'm using inheritance aswell, things get really complex. Imagine that there are classes Y and Z that are derived from X, each having extra methods that should only be called from either A or B. It means that I have to build multiple interface hierarchies. In the end, it just makes things really really complex, only for the sake of keeping some methods hidden.

It's not a good practice in general when a single class used by several clients completely differently. Seems that there should be two classes.


@Mirage: Can you show me an example of aggregation? I've heard that word often, but I don't really know how it solves my problem. Thanks! :)

Sure. Aggregation is the same as composition:


type
TA = class
procedure P();
procedure Q();
end;

TB = class
procedure R();
procedure S();
end;

TX = class()
private
FA: TA;
FB: TB;
public
property ForA: TA read FA;
property ForB: TB read FB;
end;


Here two aggregated classes are used to serve different clients.
Methods can be called like this: X.ForA.P(), X.ForB.R(), etc.

Also you can aggregate the X class. Example with interface delegation which Delphi supports:



type
IXForA = interface
procedure P();
procedure Q();
end;

IXForB = interface
procedure R();
procedure S();
end;

implementation

type
TX = class
private
procedure P();
procedure Q();
procedure R();
procedure S();
end;

TA = class(TInterfacedObject, IXForA)
private
FX: TX;
public
property X: TX read FX implements IXForA;
end;

TB = class(TInterfacedObject, IXForB)
private
FX: TX;
property X: TX read FX implements IXForB;
end;


This way methods can be called as A.P() where A: IXForA;

The both aggregation approaches can use or do not use interfaces and/or delegation.