Let’s start with a simple example — a Tic-tac-toe game. For starters, the game has a 3x3 grid on which two players place Os and Xs (a.k.a noughts and crosses) alternatively. The player who captures 3 consecutive tiles horizontally, vertically or diagonally wins the game.

Now that we have established the basics, let’s create a simple UI on Android. The layout has 9 buttons placed in a 3x3 arrangement. Whenever a user clicks on one of those buttons, we should let the game logic know which button was tapped. Nothing complex, nothing new, just a straight forward implementation.

A humble Tic-tac-toe game

Each button has an ID and is bound to the onTicTacToeTileClick(View) method using Butter Knife’s @OnClick annotation. Inside the method, we retrieve the ID of the button that was clicked and transform it into information that can be understood by the game logic. That’s all. Now, let’s look into some of the different ways in which we can tackle this problem.

Ladders ( if … else )

if … else is one of the control flow structures that can help us with this scenario. However, it could get really verbose when dealing with a large number of conditions.

if…else statements for buttons in rows 2 and 3 are omitted for brevity

Notice in the above example, I have truncated conditions for buttons in rows 2 and 3 starting from line 16, for the sake of brevity.

I would also like to establish the fact that there is nothing wrong with the if … else control structure or this approach. This is one of the correct ways to solve the problem at hand. However, there are times where it could become unintuitive to make changes or could compromise readability.

Switches

The switch control structure is also suitable to solve this problem. It is less verbose and offers better readability than its if … else counterpart. Again, nothing wrong this with approach as well.

case statements for buttons in rows 2 and 3 are omitted for brevity

Anonymous Data Structures

Now, apart from using if … else and switch there is another way of tackling this situation — Anonymous Data Structures. To make this work, we pick an appropriate data structure, extend it anonymously and use an initializer block to populate it.

The following example uses a HashMap<Integer, Pair<Integer, Integer>> whose keys are view IDs and values are button coordinates (row index, column index).

Anonymous HashMap with an initializer block

In the modified onTicTacToeTileClick(View) method, we get the ID of the button that was clicked and then attempt to retrieve the button’s coordinate from the HashMap . This code is more readable and easier to maintain.

The null check on line 7 is equivalent to the last else part in if … else ladder or the default case in the switch control structure.

When the keys are integers, I prefer a SparseArray over a Map implementation on Android.

It is also to be noted that there are always trade-offs. Using a data structure brings in additional memory requirements which in most cases should be trivial. If your data structure has large retrieval times and performance is a concern, this pattern may not be suitable.

The pattern truly shines when used with functional interfaces, lambda expressions and method references. It can also encapsulate and provide elegant abstractions in certain scenarios.

If you enjoyed this article please hit the little ❤ below.