(Basic) Improving the ever growing class with "Dictionary" and "Enumeration"
Bài đăng này đã không được cập nhật trong 3 năm
Background
In my previous article, I've tried to describe what a human class can be. Besides some basic attributes like 'name' and 'id' (from their first ancestor, the "thing"), and some from their direct parent (age, health points and stamina), human has their own attribute too, 'intelligence'. Of course those attributes alone could not help humans to survive this world, let alone creating such a civilization. They also need strength, agility, will, you name it. So, let's improve the human race with these useful attributes, before an alien force attacks us!
"But I cannot think of it all right now. May we continue with the ones you mentioned instead, and then go back here again when I have another one to add?"
Hmm, it'll cost you the entire code anytime you change the abstraction. Don't believe me, huh? Ok, let's see.. For you interface lovers, please follow me to get along through these long codes. And for fans of the class, just sit there for a moment, ok? And watch.. :
public interface IHuman : IBeing
{
int Intelligence { get; }
int Strength { get; } //add this one
int Agility { get; } //and then this one
int Will { get; } //and this one, ok done!
}
public class Human : IHuman
{
int id, age, healthPoints, stamina, intelligence;
string name;
int strength, agility, will; //add this one
public Human(int id, string name, int age, int stamina, int intelligence,
int strength, int agility, int will) //and this one
{
this.id = id;
this.name = name;
this.age = age;
this.stamina = stamina;
this.intelligence = intelligence;
this.healthPoints = 100;
this.strength = strength; //this one
this.agility = agility; //this one
this.will = will; //and this one
}
public int Id
{
get { return id; }
}
public string Name
{
get { return name; }
}
public int Age
{
get { return age; }
}
public int HealthPoints
{
get { return healthPoints; }
}
public int Stamina
{
get { return stamina; }
}
public int Intelligence
{
get { return intelligence; }
}
//and let's start adding the entire codes below
public int Strength
{
get { return strength; }
}
public int Agility
{
get { return agility; }
}
public int Will
{
get { return will; }
}
//pheew... it's done. Right?
}
public void CallTheImprovedConstructor()
{
Human tonyStark = new Human(1, "Tony Stark", 30, 50, 170,
55, 50, 500); // these are the additional params we must passed, or VS won't let us go peacefully
}
"Ok.. just give me a minute.. to catch my breath..". Sorry for that, guys. I told you in the beginning, remember? So, will you get back to the beginning, when there's another new idea comes across your mind? "You could kill me, man!"
"Ok, so, is there any other way, a more efficient way, to do this?" Yes, there is.
Improving the human race is not that painful, thou
What if, an attribute is only a mere constant? Like 1,2,3, or true and false. Think of it as a set of attributes. A set that contains 'Intelligence', 'Strength', 'Agility' and 'Will'.
Now, this is the time to show you what you can do, class followers, and let the interface lovers rest for awhile. Let's start with redefining the human class first :
public abstract class CHuman : CBeing
{
//public abstract int Intelligence { get; } //let's get rid of this old rigid way to declare an attribute
public abstract IDictionary<string, int> Attribs { get; }
}
"Dictionary"? Yes, .NET calls it a "dictionary". Remember when you want to understand an English word or two, and get a dictionary to help you? It's similar, more or less (I suppose.. or, at least, Microsoft suppose to think so). You need this because you want to keep the data in a key-value pair format (in this case, the name of the attributes and its values).
How high is his "intelligence"? Answer : 170. How high is his "strength"? Answer : 55. How high is his "agility"? Answer : 50. You need to keep this data this way :
{
("Intelligence", 170),
("Strength", 55),
("Agility", 50)
}
This is the case where a dictionary will come in handy. Got that, class lovers? Great!
Now, let's continue with changing the classification of the human race, quite like this :
public class Human : CHuman
{
int id, age, healthPoints, stamina;
//, intelligence; //we don't need this anymore
string name;
Dictionary<string, int> attribs; //right now we keep all the attributes here
public Human(int id, string name, int age, int stamina,
Dictionary<string, int> attribs) //pass all the attributes here
//int intelligence) //so we can remove this specific hardcoded param
{
this.id = id;
this.name = name;
this.age = age;
this.stamina = stamina;
this.attribs = attribs;
this.healthPoints = 100;
}
public override int Id
{
get { return id; }
}
public override string Name
{
get { return name; }
}
public override int Age
{
get { return age; }
}
public override int HealthPoints
{
get { return healthPoints; }
}
public override int Stamina
{
get { return stamina; }
}
//remove this property below
//public override int Intelligence
//{
// get { return intelligence; }
//}
//and add this new more flexible property to keep the attributes
public override IDictionary<string, int> Attribs
{
get { return attribs; }
}
}
Cool, isn't it? We even haven't declared any attribute yet! No intelligence. No strength. No nothing! Why? Because right now we will deal with all of the human attributes later, in the instantiation layer, not in the abstraction layer. So, the code would be like this :
var attribs = new Dictionary<string, int>(); //create the initial dictionary first
attribs.Add("Intelligence", 170); //and add a new attribute 'intelligence' with its initial value 170
attribs.Add("Strength", 55); //add a new attribute 'strength' with its initial value 55
attribs.Add("Agility", 50); //add a new attribute 'agility' with its initial value 50
attribs.Add("Will", 500); //finally, add a new attribute 'will' with its initial value 500
Human tonyStark = new Human(1, "Tony Stark", 30, 50, attribs); //now invoke this constructor this way
Yeaaay..! Now we can add as many attributes as we want, without the need to make any groundbreaking changes in the abstraction layers! How cool is that, huh?
Do you wanna see something cooler?
Enumeration to the rescue
Have you ever gone through an annoying bug because of a typo? What if you mistyped "Intelligence" with "Inteligence" (with single 'L')? Visual Studio (VS) couldn't understand that you just made an error and it will always give you a green light in every compilation attempt. Care to try somethin smarter?
Let VS help you by using an "enumeration" like this :
public enum Attrib
{
Intelligence,
Strength,
Agility,
Will
}
And let's change a bit our human class :
public class Human : CHuman
{
int id, age, healthPoints, stamina;
string name;
Dictionary<Attrib, int> attribs; //we use the enumeration here
public Human(int id, string name, int age, int stamina,
Dictionary<Attrib, int> attribs) //and don't forget with this one too
{
this.id = id;
this.name = name;
this.age = age;
this.stamina = stamina;
this.attribs = attribs;
this.healthPoints = 100;
}
public override int Id
{
get { return id; }
}
public override string Name
{
get { return name; }
}
public override int Age
{
get { return age; }
}
public override int HealthPoints
{
get { return healthPoints; }
}
public override int Stamina
{
get { return stamina; }
}
//and this is the last one we need to change
public override IDictionary<Attrib, int> Attribs
{
get { return attribs; }
}
}
Nice..! Let's see what the instantiation will look like, now :
var attribs = new Dictionary<Attrib, int>(); //create the initial dictionary first
attribs.Add(Attrib.Intelligence, 170); //and add a new attribute 'intelligence' with its initial value 170
attribs.Add(Attrib.Strength, 55); //add a new attribute 'strength' with its initial value 55
attribs.Add(Attrib.Agility, 50); //add a new attribute 'agility' with its initial value 50
attribs.Add(Attrib.Will, 500); //finally, add a new attribute 'will' with its initial value 500
Human tonyStark = new Human(1, "Tony Stark", 30, 50, attribs); //now invoke this constructor this way
See that? No more typo from now on! The bonus? Visual Studio will even help you with its ever popular "Intellisense" feature, to get you code faster than ever. Honestly, Intellisense is one of the reason I don't wanna get back to VS 6.0. Seriously!
So, let's wrap it up!
###In short, enumeration will help you stick in the corridor. You just cannot make any mistake with that. That's the case if you can name every member, including the future members, of the set, but if it's a subset of any other set, and there is no way to predict the data, just don't use it.
###Meanwhile, dictionary is a very neat feature of .NET to build a list in a key-value pair format, so we could easily store values and get them back by referring to its name.
I think we can let Tony Stark on his own for awhile now. Next, how about making use of the other base classification left, the "matter", to create many useful things for him to enhance himself? How about building a modern high-tech "factory" to produce these things for him? Including errr.. the Iron Man Suite, for example? "Hell yeeah.. Next article, please!"
All rights reserved