(Basic) The very first fully functional "Factory"
Bài đăng này đã không được cập nhật trong 3 năm
Background
Let Tony Stark on his own for a moment and let's get to another base class we have, the "matter". What can we do with it? What do you have in mind? How about something that related to human beings? Something that can be attached to them, for example, so we could see how well these two kinds of things co-exists together in this universe.
How about something wearable? Like clothes, accessories, or even.. a suite? Sounds interesting?
The wearable we could dream of
Have you ever seen the awesome ExoSkeleton suite? No? Just Google it, will you. It is designed to help people with disabilities to act like normal people, and even more.
So, what kind of wearable you could dream of?
Ok now, fans of the class, let me refresh your memory first about the "matter" base class, with its own "durability" attribute there :
public abstract class CThing //This is the ancestor of all things
{
abstract public string Name { get; }
abstract public int Id { get; }
}
public abstract class CMatter : CThing
{
public abstract int Durability { get; }
}
If you still remember my previous article about Enumeration and Dictionary, you are all set, because this time, we will use those features, extensively.
Wearables can be categorized by its type and how you wear it. Like hats, where you always wear it on top of your head. Eyeglass in front of your eyes. Apparel for your upper body. Full-body costumes, and so on. So, how about separating it into two lists like this :
public enum WearableType
{
Hat,
Mask,
Eyeglass,
Earring,
Masker,
Necklace,
Apparel,
Gauntlet,
Ring,
Belt,
Trousers,
Shoes,
Costume
}
public enum BodyPart
{
Head,
Eye,
Ear,
Mouth,
Neck,
UpperBody,
Hands,
Finger,
Waist,
Legs,
Foot,
FullBody
}
Cool, right? Your list could be better than mine. But, don't push yourself to finish this list for now, because we can get back here at anytime for that. Let's get to the definition of the "wearables" itself.
So, the definition of the "wearable" class, maybe won't go too far from this one :
public enum Attrib //Remember this Enum? We use it again here
{
Intelligence,
Strength,
Agility,
Will
}
public abstract class CWearable : CMatter
{
public abstract BodyPart CorrespondingBodyPart { get; }
public abstract IDictionary<Attrib, int> AttributeModifiers { get; }
}
You could see there are two new attributes specific to the "wearable" class there. The "corresponding body part" which can be used to guide any human about how to wear that thing, and the "attribute modifiers", that can improve the basic attributes of the wearers, to help them to survive. Like the above exoskeleton, for example, that can alter your strength and ability. Or, even any memorabilia like a pendant, that can boost your will. Getting excited now?
So, let's create some implementations of the wearable class, then. What's your call? I will go with 'Hat' and 'Costume' first :
public class Hat : CWearable
{
protected int id, durability;
protected string name;
public Hat(int id, string name, int durability)
{
this.id = id;
this.name = name;
this.durability = durability;
}
public override int Id
{
get { return id; }
}
public override string Name
{
get { return name; }
}
public override int Durability
{
get { return durability; }
}
public override BodyPart CorrespondingBodyPart
{
get { return BodyPart.Head; } //You put this thing on top of your head
}
public override IDictionary<Attrib, int> AttributeModifiers
{
get { return null; } //A hat is a hat. It won't improve any of your attributes, whatsoever.. (maybe your awesomeness, a little)
}
}
public class Costume : CWearable
{
protected int id, durability;
protected string name;
protected Dictionary<Attrib, int> attributeModifiers;
public Costume(int id, string name, int durability, Dictionary<Attrib, int> attributeModifiers)
{
this.id = id;
this.name = name;
this.durability = durability;
this.attributeModifiers = attributeModifiers;
}
public override int Id
{
get { return id; }
}
public override string Name
{
get { return name; }
}
public override int Durability
{
get { return durability; }
}
public override BodyPart CorrespondingBodyPart
{
get { return BodyPart.FullBody; } //You use this thing with your whole body
}
public override IDictionary<Attrib, int> AttributeModifiers
{
get { return attributeModifiers; }
}
}
I need you to examine closely, how these two kinds of wearables actually declare their own constructor, their own "corresponding body part" and the "attribute modifiers". How a hat must be placed on your head, and how you wear a costume with your entire body. How a hat will never have any attribute modifier in any way (see its constructor). Makes sense? Now we are ready to place an order for those two. "Order?" Yes, order. "Not, 'create'?" No. I'll show you. Shall we?
The factory of things
Because we already got the description of the "wearables" we need, now it's the time to build 'the' "factory" itself. The one and only source to get all those wearables, so we don't need to create them by ourselves. See? Sometimes monopoly could only simplify things.
How should we build this factory? First, create the factory class itself, and add a "static method" to be called everytime we need new wearables. Pretty much like this :
public class WearableFactory
{
public static CWearable GiveMe(WearableType wearableType, int id, string name, int durability, Dictionary<Attrib, int> attributeModifiers)
{
CWearable theWearable = null;
if (wearableType == WearableType.Hat)
{
theWearable = new Hat(id, name, durability);
}
else if (wearableType == WearableType.Costume)
{
theWearable = new Costume(id, name, durability, attributeModifiers);
}
return theWearable;
}
}
Fantastic! Now the factory is ready to serve us! Wanna try some? Remember my article about unit test? So, let's ask for an "ExoSkeleton" then!
[TestMethod]
public void AskTheSimpleFactoryForExoSkeleton()
{
var attributeModifiers = new Dictionary<Attrib, int>();
attributeModifiers.Add(Attrib.Strength, 300);
attributeModifiers.Add(Attrib.Agility, 250);
//Let's ask the factory for an exoskeleton costume
var ExoSkeleton = WearableFactory.GiveMe(WearableType.Costume, 1, "ExoSkeleton", 100, attributeModifiers);
//and test wether it is really an exoskeleton costume we ask for
Assert.IsInstanceOfType(ExoSkeleton, typeof(Costume));
Assert.AreEqual(BodyPart.FullBody, ExoSkeleton.CorrespondingBodyPart);
Assert.AreEqual(100, ExoSkeleton.Durability);
Assert.AreEqual(300, ExoSkeleton.AttributeModifiers[Attrib.Strength]);
Assert.AreEqual(250, ExoSkeleton.AttributeModifiers[Attrib.Agility]);
}
There you are. An exoskeleton costume with 100 points durability, and two attribute modifiers of strength and agility, with 300 and 250 points each.
Or, a cowboy hat, anyone?
[TestMethod]
public void AskTheSimpleFactoryForACowboyHat()
{
//Let's ask the factory for a cowboy hat
var CowboyHat = WearableFactory.GiveMe(WearableType.Hat, 1, "CowboyHat", 5, null);
//and test wether it is really a cowboy hat we ask for
Assert.IsInstanceOfType(CowboyHat, typeof(Hat));
Assert.AreEqual(CowboyHat.CorrespondingBodyPart, BodyPart.Head);
Assert.AreEqual(5, CowboyHat.Durability);
}
You got it. This is your cowboy head. It only has 5 points of durability, so please take care of it.
So, what's the point?
###Let's see.. hmmm.. just like I said, we don't need to create things by ourselves anymore. No "new" keyword anywhere else because the instantiation is already handled by the factory. We can let it go, because all we have to do now is ASK.
###This is one of the "Creational Patterns" out there. That is, patterns that deal with how to create things. In this case, they call this pattern a "Simple Factory" pattern. The very basic factory pattern out there.
"So, you mean we can still enhance this factory?" The answer is YES, ABSOUTELY! "How?". See you in my next topic, guys!
All rights reserved