Reputation: 791
I am creating a simple game that contains classes called 'Player' and 'Strategy'. I want to assign a Strategy instance to the Player instance when the Player is created.
class Player(object):
def __init__(self):
self.Strategy = None
def Decision(self, InputA, InputB):
Result = self.Strategy(InputA, InputB)
return Result
def SetStrategy(self):
# Sets a strategy instance to the Player instance
class Strategy(object):
def Strategy1(self, InputA, InputB):
return InputA * InputB
def Strategy2(self, InputA, InputB):
return (InputA - InputB) / 2
def Strategy3(self, InputA, InputB):
return 0
What I'm trying to achieve:
in[0] Player1 = Player()
in[1] Player2 = Player()
in[2]: Player1.SetStrategy('Strategy1')
in[3]: Player2.SetStrategy('Strategy3')
in[4]: Player1.Decision(2,5)
out[0]: 10
in[5]: Player2.Decision(3,6)
out[1]: 0
Searching here and via google shows me ways of doing it with monkey patching but the approach looks a little inelegant (and although I'm a beginner I think there's a better way to do it) - is there a way to do this with inheritance that I'm not seeing?
Upvotes: 1
Views: 98
Reputation: 880239
def strategy1(inputA, inputB): # 2
return inputA * inputB
def strategy2(inputA, inputB):
return (inputA - inputB) / 2
def strategy3(inputA, inputB):
return 0
strategy = {
'mul': strategy1,
'diff': strategy2,
'zero': strategy3
}
class Player(object):
def __init__(self, strategy_name='mul'): # 1
self.strategy_name = strategy_name # 5
def decision(self, inputA, inputB): # 4
result = strategy[self.strategy_name](inputA, inputB)
return result
player1 = Player()
player2 = Player()
player1.strategy_name = 'mul' # 3
player2.strategy_name = 'zero'
print(player1.decision(2, 5))
# 10
print(player2.decision(3, 6))
# 0
Every player has a strategy, so don't allow instantiation of Player
without assigning some strategy. You could use a default strategy
(as shown below), or make strategy
a mandatory argument.
The strategies could be plain functions; I don't see a reason to bundle them as methods of a Strategy class. Always keep code as simple as possible; don't use a class when a function would suffice; use a class when it provides some feature (such as inheritance) which makes the class-based solution simpler.
In Python there is no need for getters/setters like setStrategy
.
You can use plain attributes for simple values, and properties to
implement more complicated behavior. Attributes and properties use
the same syntax, so you can switch from one to the other without
having to change have the class is used.
There is a convention (recommended in PEP8) that classes be named in CamelCase, and instances, functions and variables in lowercase. The convention is used ubiquitously, and following it will help other understand your code more easily.
To make it easy to store the strategy in a database, you could store
the strategy_name
in the database, and use a lookup dict (such as
strategy
) to associate the name with the actual function.
Upvotes: 1