-1

I use a Strategy pattern, so I have my Strategy abstract class, my ConcreteStrategy class and my Player class. In my ConcreteStrategy I must access my Player object.

Knowing that Player has a Strategy and that, as my teacher told me, I must not include Player in Strategy class, how can I access Player without including it in Strategy?

jaco0646
  • 15,303
  • 7
  • 59
  • 83
clst
  • 111
  • 1
  • 11
  • What about an abstract ``runStrategy(Player p)`` method in the ``Strategy`` class/interface? Either this or use a generic type to not have the word ``Player`` in the ``Strategy`` class. – f1sh Nov 14 '18 at 15:45
  • Please add some class UML class diagram if not coded something, if coded please put some snippets. That will help. – janardhan sharma Nov 14 '18 at 16:07

4 Answers4

2

You can have the Player as an instance variable of your ConcreteStrategy, eg

class PlayerStratey implements Strategy {
    Player player;
    public PlayerStrategy(Player pl) {
        player = pl;
    }
    @Override
    public void executeStrategy() {
        System.out.printf("Player %s is executing his strategy!%n", player);
    }
}

EDIT:

As for "a player has a strategy, not the other way around", that's pretty much an implementation detail to me. Here's a PlayerStrategy with an inner class:

class Player {
    Strategy strategy = new PlayerStrategy();

    // now the player "has a" strategy.
    public Strategy getStrategy() {
        return strategy();
    }

    class PlayerStrategy implements Strategy {
        @Override
        public void executeStrategy() {
            System.out.printf("Player %s is executing his strategy!%n", Player.this);
        }
    }
}

As for this being valid, it does depend on what exactly the Strategy is used for. You'd need to give us the actual interface the strategy represents.

daniu
  • 14,137
  • 4
  • 32
  • 53
  • 3
    it should not be the other way around? I mean a player has an Strategy and not a Strategy has a Player. – elbraulio Nov 14 '18 at 15:51
  • @BraulioLopez That is my question... is it really legit to do this ? – clst Nov 14 '18 at 16:35
  • @KevinV according to your teacher it is not: "as my teacher told me, I must not include Player in Strategy class" – UmshiniWami Nov 14 '18 at 16:55
  • @KevinV will you're not including the player in the strategy class, so the loose coupling is achieved, which is the point of the pattern. Ymmv with your teacher's interpretation, he might get it wrong ;) As for who has what (player /strategy), that's pretty much an implementation detail. I can provide an alternative one later. – daniu Nov 14 '18 at 17:22
0

Since the player does something that it needs the strategy for, you can pass the Player instance to the strategy method(s).

interface PlayerStratey {
    void stumble(Player p);
}

class DullPlayerStratey implements PlayerStratey {
    @Override
    public void stumble(Player p) {
        p.move(ThreadLocalRandom.current().nextBoolean() ? -1 : 1);
    }
}
Mark Jeronimus
  • 9,278
  • 3
  • 37
  • 50
0

You should inject the concrete strategy in your player Class via the Strategy interface. The Strategy then takes a player as argument:

1- the Interface:

public interface Strategy {
    public void apply(Player player);
}

2- Concrete strategies:

public class StrategyOne implements Strategy{

    public void apply(Player player) {
        System.out.println(this.getClass().getSimpleName() +" on " + player.getName());
}

   public class StrategyTwo implements Strategy {

    public void apply(Player player) {
        System.out.println(this.getClass().getSimpleName() +" on " + player.getName());
    }
}

3- Context (here your player class):

public class Player {
    private Strategy strategy;
    private String name;

    public String getName(){
        return name;
    }

    public Player(Strategy strategy, String name){// construct using your chosen strategy
        this.strategy = strategy;
        this.name = name;
    }

    public void executeStrategy(Player player){
        System.out.print("Player "+ this.getName()+ " applies ");
        strategy.apply(player);
    }
}

public static void main(String[] args) {
    Player playerOne = new Player(new StrategyOne(), "playerOne");
    Player playerTwo = new Player(new StrategyTwo(), "playerTwo");
    playerOne.executeStrategy(playerOne);
    playerOne.executeStrategy(playerTwo);
    playerTwo.executeStrategy(playerTwo);
    playerTwo.executeStrategy(playerOne);
}

5- Output:

Player playerOne applies StrategyOne on playerOne

Player playerOne applies StrategyOne on playerTwo

Player playerTwo applies StrategyTwo on playerTwo

Player playerTwo applies StrategyTwo on playerOne

Then you have your player applying the strategy that's been assigned to him on the player targeted by the strategy.

UmshiniWami
  • 69
  • 1
  • 8
  • that don't really answer my problem... – clst Nov 14 '18 at 16:25
  • From what I understood of your problem you want to use a strategy pattern in which the Player uses a given strategy. In this case, the Player is dependent on the chosen strategy. Do you mean you are trying to have the Strategy depend on the Player? – UmshiniWami Nov 14 '18 at 16:42
  • In short my answers to "how can I access to Player without including it in my Strategy ?" is you don't. The Player accesses the strategy as you hinted: "knowing that Player have a Strategy" – UmshiniWami Nov 14 '18 at 16:50
  • @KevinV Ok I think I understand what you mean now =) have a look at the updates – UmshiniWami Nov 14 '18 at 19:59
0

You can create an abstraction for the Player class (read about Dependency Inversion for more info) and pass it as an argument to the Strategy abstract class. This way, the details remain decoupled.

If you really need to avoid the circular dependency, you can try to extract from the Player class whatever you need to use in your strategies to a new class, and then pass it as an argument through a method (or constructor) on the Strategyclass.

Ricardo Costeira
  • 3,171
  • 2
  • 23
  • 23