Resolved Question regarding the instantiation of object in class

Matthieu

Member
Joined
Aug 15, 2020
Messages
23
Programming Experience
Beginner
Hi erveryone,

I got a question I want to clarify by using an example.

I have a Club class and a TennisPlayer class. A club can have many tennisplayers as members to that club, and a tennisplayer can only be member at one club at a time.
My classes would look like this. I simplified the classes for this example.

C#:
public class Club
    {
        private List<TennisPlayer> members;

        public Club()
        {
            members = new List<TennisPlayer>();
        }

        public void AddTennisPlayerAsMember(TennisPlayer tennisPlayer)
        {
            members.Add(tennisPlayer);
            tennisPlayer.Club = this;
        }
    }


C#:
public class TennisPlayer
    {
        public string Name;
        public Club Club;

        public TennisPlayer(string name, Club club)
        {
            Name = name;
            club.AddTennisPlayerAsMember(this);
        }
    }

So my question is, is it right that in the TennisPlayer class the field club has nothing like Club club = new Club()?
Cause if I would do that, every TennisPlayer object I instantiate would have his own Club object which is not logical because there is only one Club object for every club, just like there is in real life no duplicate of the same club, am I right?
 
is it right that in the TennisPlayer class the field club has nothing like Club club = new Club()?
That is right, the player should not be the interface to create a new club.

Also, in your player class the constructor sets the club by parameter. Beware the argument may be null if no club is to be assigned, that will cause NullReference exception on the AddTennisPlayerAsMember call, which can easily be handled with null-conditional operator: Member access operators and expressions - C# reference
C#:
club?.AddTennisPlayerAsMember(this);
 
That is right, the player should not be the interface to create a new club.

Also, in your player class the constructor sets the club by parameter. Beware the argument may be null if no club is to be assigned, that will cause NullReference exception on the AddTennisPlayerAsMember call, which can easily be handled with null-conditional operator: Member access operators and expressions - C# reference
C#:
club?.AddTennisPlayerAsMember(this);
Thanks for your answer. Now I know I'm on the good track.

Now assume that class Club has an extra field Name (the name of the club).
Imagine I create a Club object 'c' and a Tennisplayer object 't'. By using the constructor of the t I link t to c.
Trough t I can now reach c and acces the field Name (t.Club.Name), so that's ok. This is handy if i want to know the clubname of tennisplayer object.
But now I can also reach the method AddTennisPlayerAsMember through t (t.Club.AddTennisPlayerAsMember) and that's not ok.
because now I can alter a club by using a tennisplayer object.
So my idea is to make the field Club in the TennisPlayer class private, so i'ts not accessible outside of his class, but now I can't reach the clubname trough a TennisPlayer object.
How should you take care of this 'issue'. I could make a property Clubname in the class TennisPlayer and give this a value but it looks a little bit strange or is this common?
 
Fields should always be private, use properties to expose the field values (object state) to the outside. Properties can also be declared read-only.
 
How do you plan to define each club which a tennis player is a member of? In your club object, you have no name of which club the class club object represents. This will be a problem if you have multiple clubs.

Drop line 4 from your TennisPlayer class. It has no purpose there, and it breaks the rule of single responsibility purpose.

You should consider making use of having an abstract class to base your other classed on. I'd sit down and write it out on paper first. Then when you have it in your head, write it out in code.
 
Fields should always be private, use properties to expose the field values (object state) to the outside. Properties can also be declared read-only.

I understand I have to work with properties, but I can' manage to secure the list members of the club class.

C#:
public class Club
    {
        public string Name;
        public List<TennisPlayer> Members { get; }

        public Club(string name)
        {
            Name = name;
            Members = new List<TennisPlayer>();
        }

        public void AddMember(TennisPlayer tennisPlayer)
        {
            Members.Add(tennisPlayer);
            tennisPlayer.Club = this;
        }

    }

C#:
public class TennisPlayer
    {
        public Club Club { get; set; }

        public TennisPlayer(Club club)
        {
            Club.AddMember(this);
        }
    }

C#:
class Program
    {
        static void Main(string[] args)
        {
            Club club = new Club("Laagland");
            TennisPlayer tennisPlayer = new TennisPlayer(club);
            tennisPlayer.Club.Members.Add(tennisPlayer);
        }
    }

As you can see, through the tennisplayer object I can reach and alter the memberst list of the club a player is member of
But I can't declare the members list private because than I can't rach it through a club object, which should be ok.
 
public List<TennisPlayer> Members { get; }
This means the list object can't be set from outside, still the contents of the list can be freely manipulated from outside. One way to solve this is to keep the list in a private field, using public methods to add/remove members, and a readonly property that only returns a copy of list content (as array).
 
a tennisplayer can only be member at one club at a time
This limitation can be mitigated by the method that adds a player to a club, it the player already has a club the method can also remove the player from the existing club first.
pseudo clode:
tennisPlayer.Club?.RemovePlayer(tennisPlayer);
 
This means the list object can't be set from outside, still the contents of the list can be freely manipulated from outside. One way to solve this is to keep the list in a private field, using public methods to add/remove members, and a readonly property that only returns a copy of list content (as array).
But a Tennisplayer still have a Club object, right? so if I keep the members list in a private field, it's correct that I can no longer alter the list directly, but now I can alter the list by using the public methods add/remove members. This way a TennisPlayer object cann still alter a club.
 
Let each of your classes have a single point of focus. A single purpose.
A tennis player should not be holding any info on the club they are in.
A club should hold no data on the tennis players in its clubs.
 
Let each of your classes have a single point of focus. A single purpose.
A tennis player should not be holding any info on the club they are in.
A club should hold no data on the tennis players in its clubs.
I'm new to the SRP, and quite a newbie :). But imagine a class Author and a class Book. A book does have an author so a book class contains a author object, right?
Following SRP I may not declare an author object in the book clas? I find it quite strange certainly for a beginner in OOP.
 
But imagine a class Author and a class Book. A book does have an author so a book class contains a author object, right?
That's why we sometimes use abstraction. But if you want to keep to SRP, then you will want to keep your classes strictly about the details of their purpose. In your case, they appear to be details about A) the club, and B) the tennis player.

There are many ways you can do what you are doing, including using inheritance, to inherit object values from another class while keeping relative to SRP.

One way you could have wrote it would be as the following code is demonstrated. Create a club object and only use what is required to create a club object, in this example, I will use three properties. Code is commented so you can hover over it in VS and it will tell you what each part is doing :
C#:
    public class Club
    {
        public string ClubName { get; set; }
        public string ClubAddress { get; set; }
        public string ClubPhoneNumber { get; set; }
        /// <summary>
        /// The Club class is inisialised with a new instance of a club object and its details are provided upon instanciation.
        /// </summary>
        /// <param name="clubName">The name of the club is provided here</param>
        /// <param name="clubAddress">The club address is provided here</param>
        /// <param name="clubPhoneNumber">The clubs phone number is provided here</param>
        public Club(string clubName, string clubAddress, string clubPhoneNumber)
        {
            ClubName = clubName ?? throw new ArgumentNullException(nameof(clubName));
            ClubAddress = clubAddress ?? throw new ArgumentNullException(nameof(clubAddress));
            ClubPhoneNumber = clubPhoneNumber ?? throw new ArgumentNullException(nameof(clubPhoneNumber));
        }
    }
Next you need the same thing from your Tennis player; a name, address, and maybe a phone number...
C#:
    public class TennisPlayer
    {
        public string PlayerName { get; set; }
        public string PlayerAddress { get; set; }
        public string PlayerPhoneNumber { get; set; }
        /// <summary>
        /// The TennisPlayer class is inisialised with a new instance of a TennisPlayer object and its details are provided upon instanciation.
        /// </summary>
        /// <param name="playerName">The name of your tennis player</param>
        /// <param name="playerAddress">The address of your tennis player</param>
        /// <param name="playerPhoneNumber">The phone number of your tennis player</param>
        public TennisPlayer(string playerName, string playerAddress, string playerPhoneNumber)
        {
            PlayerName = playerName ?? throw new ArgumentNullException(nameof(playerName));
            PlayerAddress = playerAddress ?? throw new ArgumentNullException(nameof(playerAddress));
            PlayerPhoneNumber = playerPhoneNumber ?? throw new ArgumentNullException(nameof(playerPhoneNumber));
        }
    }
Next, you want some type of controller class. Something where you can add and delete tennis players from clubs. What I would also recommend is adding a model class for all your data. This model would be then bind to your UI. But this is not implemented in this example. The main purpose here was to demonstrate keeping your class objects relative to what they represent :
C#:
    /// <summary>
    /// Here you can use an additional class to work with the objects of your other classes; such as Club, and TenniPlayer.
    /// This class can add your tennis players to a list of tuple TennisPlayer, Club. When this class is first instanciated,
    /// keep a copy of the instanciated object to pass around your application. New instances of this class will create a new instance of _PlayerClubPair.
    /// </summary>
    public class WithMembersOfClubs
    {
        /// <summary>
        /// This list keeps track of your tenis players and the clubs they are in.
        /// </summary>
        private List<Tuple<TennisPlayer, Club>> _PlayerClubPair = new List<Tuple<TennisPlayer, Club>>();
        /// <summary>
        /// This method will add players to your _PlayerClubPair list and store the values of your tennis player and club in a tuple<Tuple<TennisPlayer, Club>>.
        /// </summary>
        /// <param name="tennisPlayer">This is where you pass in the tennis player object</param>
        /// <param name="clubName">This is where you pass in the club object</param>
        public void AddTennisPlayerAsMember(TennisPlayer tennisPlayer, Club clubName)
        {
            _PlayerClubPair.Add(Tuple.Create(tennisPlayer, clubName));
        }
        /// <summary>
        /// This method will remove all references of a TennisPlayer object where the tuple item variable matches the tennisPlayer.Player name variable.
        /// </summary>
        /// <param name="tennisPlayer">This is where you pass in the tennis player you wish to remove</param>
        public void RemoveTennisPlayerAsMember(TennisPlayer tennisPlayer)
        {
            _PlayerClubPair.RemoveAll(t => t.Item1.PlayerName == tennisPlayer.PlayerName);
        }
        /// <summary>
        /// This method allows you to check the number of members in a given club object.
        /// </summary>
        /// <param name="clubName">The name of the club you want to check the number of players in</param>
        /// <param name="number">The number variable will be used to count how many members are in a given club</param>
        /// <returns></returns>
        public int NumberOfMembers_In(string clubName, int number)
        {
            number += (_PlayerClubPair.Where(club => club.Item2.ClubName == clubName)).Count();
            return number;
        }
To use this code, you only need to call the constructors of your club and tennisplayer objects, and pass them to another class where the data is "managed" like a controller would manage data in a web app, and from there you would generally update a model, and as I said, that model would be then bind to your UI, where your UI would automatically be updated upon new data entered into it. A sample of running the code would be as follows :
C#:
            Club club = new Club("Bondi Club", "33 Bondibeach Park", "0123456789");
            TennisPlayer tennisPlayer1 = new TennisPlayer("Sheepings", "Sheep ville", "0234567890");

            WithMembersOfClubs membersOfClubs = new WithMembersOfClubs();
            membersOfClubs.AddTennisPlayerAsMember(tennisPlayer1, club);
            TennisPlayer tennisPlayer2 = new TennisPlayer("Bob", "Bob ville", "3214567890");
            membersOfClubs.AddTennisPlayerAsMember(tennisPlayer2, club);

            Debug.WriteLine(string.Join(" ", $"{club.ClubName} has", membersOfClubs.NumberOfMembers_In(club.ClubName, 0), "Members"));

            membersOfClubs.RemoveTennisPlayerAsMember(tennisPlayer1);

            Debug.WriteLine(string.Join(" ", $"{club.ClubName} has", membersOfClubs.NumberOfMembers_In(club.ClubName, 0), "Members"));

Further references you should read up on are :
.
and

Note; while I didn't go into abstraction in this example, I did however keep it relatively close to how you already constructed your code. But, you could have used a abstract data layer and still achieve the same goal. That approach is quite different to the example above, yet still worth educating yourself on.
 

Latest posts

Back
Top Bottom