View Poll Results: What do you do when you encounter the problem I described?

Voters
4. You may not vote on this poll
  • Make sure all methods are only call-able from the right modules, at all cost

    0 0%
  • Just make the methods public for the sake of simplicity

    4 100.00%
Results 1 to 8 of 8

Thread: Hiding methods that shouldn't be call-able.

  1. #1

    Hiding methods that shouldn't be call-able.

    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
    Last edited by chronozphere; 21-01-2011 at 11:21 AM.
    Coders rule nr 1: Face ur bugz.. dont cage them with code, kill'em with ur cursor.

  2. #2
    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?
    Peregrinus, expectavi pedes meos in cymbalis
    Nullus norvegicorum sole urinat

  3. #3
    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.
    Coders rule nr 1: Face ur bugz.. dont cage them with code, kill'em with ur cursor.

  4. #4
    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.

  5. #5
    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
    Last edited by virtual; 21-01-2011 at 05:57 PM.

  6. #6
    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:
    Code:
    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.

  7. #7
    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.

    @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!
    Coders rule nr 1: Face ur bugz.. dont cage them with code, kill'em with ur cursor.

  8. #8
    Quote Originally Posted by chronozphere View Post
    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.

    Quote Originally Posted by chronozphere View Post
    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.

    Quote Originally Posted by chronozphere View Post
    @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:
    Code:
    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:

    Code:
     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.

Bookmarks

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •