C# 7 and .NET Core 2.0 Blueprints
上QQ阅读APP看书,第一时间看更新

Putting it all together

Now, let's have a look how we use the classes to create the Cricket Score Tracker app. The buttons below the Batters section and Bowler section are used to select batsmen and a bowler for the specific over.

While each button is taken care of by its own click event, they all call the exact same method. We will have a look at how that is accomplished in a moment:

Clicking on either button under the Batsmen section will display a modal dialog with a drop-down list populated with the batsmen in the team:

Similarly, when we click on the Select Bowler button, we will see the exact same modal dialog screen displayed. This time, however, it will be a list of bowlers displayed for selection:

Selecting players from the drop-down lists will populate the text on the button clicked with that player's name. This then sets up the current over with the players involved.

Take note that we are talking in terms of the classes here. We have players, but they can be batsmen or all-rounders (bowlers).

Each player will be either a batsman or a bowler (AllRounder class):

So how did we manage to make a single method return two different players? I used a method called GeneratePlayerList(). This method is responsible for creating the player list in the modal dialog that pops up. That is all that method is responsible for. In other words, it performs no other function apart from generating the player list.

Let's look at how the Default.aspx.cs file is created. For simplicity's sake, I just created two lists for each team. I also created an enum for the player selection. The code looks as follows:

public enum SelectedPlayer { Batsman1 = 1, Batsman2 = 2, Bowler = 3 } 
List<Player> southAfrica; 
List<Player> india; 

In reality, however, you would probably make the list names team1 and team2, and allow the user to select the teams from a setup screen for this game. I have not added this functionality as I am merely trying to illustrate the concepts of OOP here.

In Page_Load, I then populate the lists with players, as follows:

protected void Page_Load(object sender, EventArgs e) 
{ 
    southAfrica = Get_SA_Players(); 
    india = Get_India_Players(); 
} 

Again, for simplicity, I have hard-coded the player names and manually added them to the lists.

The Get_India_Players() method is identical to that of the Get_SA_Players() method. You can then just copy the method and change the names to your favorite cricket players or favorite cricket teams.

In reality, you would probably read this from a database of teams and players. So instead of Get_SA_Players() and Get_India_Players(), you would have a single Get_Players() method that would be responsible for reading the players into the lists.

For now, looking at the Get_SA_Players() method, we simply do the following:

private List<Player> Get_SA_Players() 
{ 
    List<Player> players = new List<Player>(); 
 
    #region Batsmen 
    Batsman b1 = new Batsman(); 
    b1.FirstName = "Faf"; 
    b1.LastName = "du Plessis"; 
    b1.Age = 33; 
    players.Add(b1); 
    // Rest omitted for brevity 
    #endregion 
 
    #region All Rounders 
    AllRounder ar1 = new AllRounder(); 
    ar1.FirstName = "Farhaan"; 
    ar1.LastName = "Behardien"; 
    ar1.Age = 33; 
    players.Add(ar1); 
    // Rest omitted for brevity 
    #endregion 
 
    return players; 
} 

Notice now that the players list is of type List<Player>, and that we are adding Batsman and AllRounder types to it. This is what the term polymorphism means. Remember that one of the aspects of polymorphism we mentioned earlier was:

During run time, a class that is derived from a base class may be treated as an object of the class it inherits. This is seen in parameters, collections or arrays.

Therefore, because Batsman and AllRounder inherit from the Player abstract class, they are treated as objects of Player for the List<Player>.

If you swing back to the section on polymorphism earlier in the chapter, you will see that this is an example of run-time polymorphism.

Moving back to the logic to select the batsman or bowler, we look to a method to generate the player list called GeneratePlayerList():

private void GeneratePlayerList(List<Player> team, Type type) 
{ 
    List<string> players = new List<string>(); 
 
    if (type == typeof(Batsman)) 
        players = (from r in team.OfType<Batsman>() 
                   select $"{r.FirstName} {r.LastName}").ToList(); 
 
    if (type == typeof(AllRounder)) 
        players = (from r in team.OfType<AllRounder>() 
                   select $"{r.FirstName} {r.LastName}").ToList(); 
 
    int liVal = 0; 
    if (ddlPlayersSelect.Items.Count > 0) 
        ddlPlayersSelect.Items.Clear(); 
 
    foreach (string player in players) 
    { 
        ListItem li = new ListItem(); 
        li.Text = player.ToString(); 
        li.Value = liVal.ToString(); 
        ddlPlayersSelect.Items.Add(li); 
 
        liVal += 1; 
    } 
} 

You will notice that the method takes a List<Player> argument as well as a Type. The method checks whether type is a Batsman or AllRounder and based on that, reads the first and last names of the players in the list.

I believe that this method can be simplified even further, but I wanted to illustrate the concept of polymorphism at work.

The actual aim is to try and write the least amount of code for the maximum required effect. As a rule of thumb, some developers maintain that if a method's length is longer than the code page you are looking at in the IDE, you need to do some refactoring.

Having less code and smaller methods allows the code to be easier to read and understand. It also allows better maintainability of that code because smaller sections of code are easier to debug. In fact, you might experience fewer bugs because you are writing smaller, more manageable pieces of code.

Many years ago, I was part of a team that worked on a project for a large corporation in Cape Town. They had a systems architect called Uthmaan Hendrix. I will never forget this guy. He was the humblest bloke I had ever come across. The documentation he created for the system we worked on was simply incredible. It took almost all the think work out of the code we had to write. The developers didn't have to decide how to architect the project at all.

This project implemented SOLID principles, and understanding the code was really easy. I still have a copy of that document. I still refer to it from time to time. Unfortunately, not all developers have the luxury of having a dedicated systems architect on the project they are working with. It is, however, good for developers to understand what the SOLID design principles are.