1

I want to make an if statement that checks to see which method made the call to a secondary method.

I will write what i want in pseudo code so you can see what I mean.

public static void methodOne() {
    methodToCall();
    }

public static void methodTwo() {
    methodToCall();
    }

public static void methodThree() {
    methodToCall();
    }

public static void methodToCall() {
    if (methodOne made the call == true) {
        execute this
    } else if (methodTwo made the call == true){
        execute this
    } else if (methodThree made the call == true){
        execute this
    } else {
        System.out.println("How did you get here?");
    }
}

That's about the gist of it. I want a simple check to see which method made the call so I can choose which operation is relevant to the call.

Is this possible?

If it is not possible, is there a work around?

gcoulby
  • 534
  • 2
  • 10
  • 20
  • 10
    Why not just pass a parameter? – Oliver Charlesworth Sep 29 '13 at 10:13
  • 3
    Why do you first delegate three method calls to a single one just to separate it again there? – isnot2bad Sep 29 '13 at 10:14
  • Coupling methods (or functions, classes, programs...) is necessary but must be under control and avoided when it's possible. – Aubin Sep 29 '13 at 10:16
  • 1
    possible duplicate of [In Java, how do I find the caller of a method using stacktrace or reflection?](http://stackoverflow.com/questions/421280/in-java-how-do-i-find-the-caller-of-a-method-using-stacktrace-or-reflection) – Johan Sep 29 '13 at 10:18
  • If you don't want to pass a parameter to methodToCall(), you may create a global variable which holds the information who called the function. `string Caller = ""; public static void methodOne() { Caller="One"; methodToCall(); }` – Aycan Yaşıt Sep 29 '13 at 10:21
  • The structure goes like this. method one two and three convert a double value to a string which are all different functions. The fourth method needs to take a string depending on the method to make the call and convert it to an array. it then looks at each character in the array and determines what character it is. I hope this is clear – gcoulby Sep 29 '13 at 10:27
  • 1
    A global variable? Where do you come from? In 1970, OK we have no choice, but today, with Object Oriented Language, global variables are banned! – Aubin Sep 29 '13 at 10:27

5 Answers5

5

This is called 'state orientation', and it was debated extensively in the 1970s, possibly even the 1960s. The conclusion was that if you need to know this sort of thing you are already doing something seriously wrong, by introducing a two-way dependency into the code. What happens for example when you add another caller?

user207421
  • 305,947
  • 44
  • 307
  • 483
4

Use three short methods, instead of combining the logic of three short methods into one larger method. Once the short methods are created Just call the appropriate method from each calling method.

public static void methodOne() {
    methodToCall1();
}

public static void methodTwo() {
    methodToCall2();
}

public static void methodThree() {
    methodToCall3();
}

public static void methodToCall1() {
    int x = 0;
    x = x - 3; //some custom logic to prep argument
    commonLogic(x);
}

public static void methodToCall2() {
    //Method 2 logic
    int x = 0;
    x = x + 3; //some custom logic to prep argument
    commonLogic(x);
}

public static void methodToCall3() {
    //Method 3 logic
    int x = 0;
    x = x * 3; //some custom logic to prep argument
    commonLogic(x);
}

public static void commonLogic(int arg1){
     //peform common logic
}

If these three methods would contain duplicate code, abstract the duplicate code into another method then call that method from within each of the smaller methods. The idea is to prepare the arguments to call the common function in each of the three smaller functions, then call the common function with those arguments.

Kevin Bowersox
  • 93,289
  • 19
  • 159
  • 189
  • 1
    This is not an answer, because the question is not a question... ;-) – Aubin Sep 29 '13 at 10:19
  • 1
    @Aubin The OP does ask if there is a work around. BTW, thanks for the edits. – Kevin Bowersox Sep 29 '13 at 10:19
  • The workaround exist (St**ckTr**e) but I don't want to write it because the question is too ambiguous and the motivations are not well defined – Aubin Sep 29 '13 at 10:22
  • @Aubin Agreed, I have used that method prior for debugging but wouldn't use that method to make logical decisions. At least not in a situation that can be solved this easily. – Kevin Bowersox Sep 29 '13 at 10:23
  • This is the method I am trying to avoid because the first two or three lines of the methodToCall1 2 & 3 will be different but then after that they will all do the same function – gcoulby Sep 29 '13 at 10:29
  • 1
    @gcoulby Then you make another method that contains the common logic. Call that method from within each of the three separate functions. So basically the three small methods prep the arguments to pass to the common function. – Kevin Bowersox Sep 29 '13 at 10:31
  • OK that seems to be the most logical. I am sorry that this is so ambiguous, but I feel I am too deep in this I can't see the simple way! – gcoulby Sep 29 '13 at 10:34
  • That edit is that answer, I'm so annoyed with myself that it's so simple. I think I need a break! – gcoulby Sep 29 '13 at 10:37
4

A great deal of the abstraction afforded by methods comes from the fact that they do not need to know who is calling them, so the answer to your question is "no". It does not mean that you cannot make it work, though: make the callers pass some sort of a token (say, an enum value) identifying themselves to the callee. This would let you dispatch on that identity inside your method's implementation:

enum CallerContext {CALLER1, CALLER2, CALLER3};
...
public static void methodToCall(CallerContext context) {
    ...
}

This is not the most Object-Oriented way of doing things, however: very often, a better approach would be letting the callers supply the logic to be executed, rather than supplying a token identifies that logic. See Visitor Pattern for details on that approach.

Sergey Kalinichenko
  • 714,442
  • 84
  • 1,110
  • 1,523
  • 1
    @dasblikenlight I like the message your conveying, but I'm not assure I agree with passing a parameter. Why add the extra baggage (argument) when simply calling another method would capture the same intent. – Kevin Bowersox Sep 29 '13 at 10:25
  • 1
    @KevinBowersox The only situation when this would make sense is when there's some code (actually, a lot of it) that precedes and follows the `if`/`then`/`else` checks on the caller. This becomes essentially a "poor man's double dispatch". I think OP removed too much details in trying to distill his code for the question, otherwise smaller, caller-specific functions would make a lot more sense than a single large function. – Sergey Kalinichenko Sep 29 '13 at 10:30
  • You are right I think my code was too distilled however, this is interesting nonetheless. I didn't know this was possible, but now also know that it is not the most advised method for my case, I can see reasons why it may be needed in other situations, so it is a valid answer – gcoulby Sep 29 '13 at 10:45
2

You can do it by examining the call stack via Thread.getStackTrace():

public static void methodToCall(Action action) {
    String callingMethod = Thread.currentThread().getStackTrace()[2].getMethodName();
    if (callingMethod.equals("methodOne")) {
        execute this0
    } else if (callingMethod.equals("methodTwo")) {
        execute this
    } else if (callingMethod.equals("methodThree")) {
        execute this
    } else {
        System.out.println("How did you get here?");
    }
}

but you shouldn't - it's a bit anti-OO. Instead, change your method signature to something like this:

public enum Action {ONE, TWO, THREE}

public static void methodToCall(Action action) {
    if (action == ONE) {
        execute this
    } else if (action == TWO) {
        execute this
    } else if (action == THREE) {
        execute this
    } else {
        System.out.println("How did you get here?");
    }
}
Bohemian
  • 412,405
  • 93
  • 575
  • 722
  • -1: "technician" answer when the debate must be treated as higher level. Even if it's possible, is it desirable? – Aubin Sep 29 '13 at 11:40
  • 1
    @aubin the question asked was "can it be done", not "should it be fine". I showed how it can be done. But I also said that you shouldn't. So what is it exactly you disapprove of here? – Bohemian Sep 29 '13 at 12:55
1

If you end up using an enum, then make sure to take advantage of the fact that enums in Java are no less than singleton instances of classes. Therefore you can declare the method as abstract in the enum definition and then override it in each instance, instead of passing the enum as a paramater to some method defined outside of the enum's context.

So it would look something like:

enum Method {

    Mode1 {
            @Override
            void call() {
                    // do stuff 
            }
    }, Mode2 {
            @Override
            void call() {
                    // do stuff differently
            }
    }, Mode3 {
            @Override
            void call() {
                    // do stuff even more differently
            }
    };

    abstract void call();
}

And then you either don't need your wrapping methods, or, if they were supposed to do anything more, you write:

public static void methodOne() {
    // some code
    Method.Mode1.call();
    // some code
}
siledh
  • 3,268
  • 2
  • 16
  • 29