[PYTHON] Design that may reduce if statement and coupling on the server side of social games

Common sight

Consider a gift box for a common game.

Item name Reason for acquisition Deadline for receipt
Herbs x 10 Clear reward for Dungeon 4 100 days left
Magic stone 4th day login bonus 100 days left
10000 gold 6th day login bonus 99 days left
Herbs x 5 Clear reward for Dungeon 3 99 days left
5000 gold This is the login bonus for the third day 96 days left
Warrior Kita This is the login bonus for the first day 93 days left

Is the schema of this DB like this? スクリーンショット 2016-12-02 18.53.56.png

Items, money, etc. are distinguished by item_type. Let's assume that this is the case.

item_type Contents
1 money
2 item
3 Character
4 Magic stone

What is the code when I receive this (when I move it from the present box to my hand)?

def acquire_present(user, present):
  if present.item_type == 1:
    """Processing to receive money"""
  elif present.item_type == 2:
   """The process of receiving an item"""
  elif present.item_type == 3:
    """Processing to receive characters"""
  ...
  else:
     raise Exception()

if statement hell. Moreover, there is a high possibility of doing various things in each receiving process (hand-held confirmation, log, etc.). This will increase the tight coupling between the acquire_present function and each data class.

Furthermore, if item_type increases due to future game expansion, it will become even longer. I want to do something about long if statements and tight couplings because they are not easy to maintain.

Separation of receiving process

Therefore, consider a class that delegates the process of receiving gifts.

class AqruireDalegatorBase(object):
  """Receive processing delegation base class"""
  @classmethod
  def acquire(user, present):
     raise NotImplementedError()

You have defined a common interface for receiving. Inherit and implement each receiving processing delegation class.

class MoneyAqruireDalegator(AqruireDalegatorBase):
 """Money receipt processing delegation class"""
  @classmethod
  def acquire(user, present):
     user.add_money(present.item_quantity)

class ItemAqruireDalegator(AqruireDalegatorBase):
 """Item receipt processing delegation class"""
  @classmethod
  def acquire(user, present):
     user.add_item(present.item_id, present.item_quantity)

...Follow other

Let's actually incorporate it into the receiving function.

def acquire_present(user, present):
  if present.type == 1:
    MoneyAqruireDalegator.acquire(user, present)
  elif present.type == 2:
    ItemAqruireDalegator.acquire(user, present)
  elif ...

By cutting out the logic to receive for each type, a feeling of loose coupling came out!

Try to make expansion easier

But the if statement is still long and I have to modify this function every time a type is added, so

DELEGATOR_MAP = {
  1: MoneyAqruireDalegator,
  2: ItemAqruireDalegator,
  ...
}

And type and delegation class mapping.

def acquire_present(user, present):
  delegator_class = DELEGATOR.get(present.item_type)
  delegator_class.acquire_present(user, present)

It's much shorter! And even if this increases the types

  1. Implement a receiving delegation class that inherits from AqruireDalegatorBase
  2. Add to DELEGATOR_MAP

It is extensible with. No need to modify the acquire_present function! All you have to do is the delegation class with the added test!

Summary (?)

Long if statements are troublesome both when investigating defects and when expanding, so if they are loosely coupled, they are kind to people now and in the future!

(Is this a facade pattern ...? It feels a bit like DI)

Recommended Posts

Design that may reduce if statement and coupling on the server side of social games
Get the width of the div on the server side with Selenium + PhantomJS + Python
This and that of the inclusion notation.
Set the color on the poster side so that the color of the Youtube subtitles changes automatically.
Drawing tips with matplotlib on the server side
Summary of versions of the Python standard library that are now server validated on https