In the previous section, we introduced the strategy pattern and used this pattern to implement an example of assigning skills based on the occupation of a role (which is, in fact, dynamically assigning methods to classes). As a fantasy RPG, with a career, we should also be able to choose a race for the character, such as: Human (Human), Elf (elf), Dwarf (Dwarf), Orc (ORC) and so on. And these four races have a very different form, the elf skin is gray, has long ears, no body hair and beard, the dwarf's skin is similar to human, but short, usually with a bushy beard, the orc has the green skin and the tall body, and the face is ugly. This article will discuss how to use Gof's abstract Factory abstraction factory to achieve this role shape design.
Implementation-oriented approach
For simplicity's sake, we assume that the character body consists of three parts: Head, Body (stature), skin (skins). So for the human structure, our first reaction naturally thought: it should be composed of Humanhead, Humanstature, Humanskin three of classes. For the sprite is similar to the design, so we implemented the following design (this article will be only for humans and Elves for example):
Abstract entity classes that make up the body
We found that each character is tightly bound to his body parts, each creating a character, we need to first create all of its composite classes (the body's entity class (Concret Class), such as Humanhead). In terms of object-oriented thinking, we think we should encapsulate this process and delegate the creation of the role part to other classes to complete. Observation, we find that although the roles are different, they are all made up of three parts, so the first step we can think of to implement this process is to abstract the entity classes that make up the body, we define three interfaces: Head, stature, Skin, three parts of the body, And let the entity classes of human and elf implement this interface:
Observed, we found that although the interface is defined, if the role human and elf are still associated with the entity class of the interface, the effect is exactly the same as for the implementation. Now, it's time to make some changes to the design, and we let Human and ELF associate with the interface, not with the implementation of the interface (OO thinking: interface-oriented programming, not implementation-oriented programming). This time, our design becomes:
At one glance, the first problem we found was that human was strikingly similar to Elf, and looked closely, and we noticed that they were exactly the same except for the names of the rest. We cannot help thinking: Is it necessary to save two identical classes of two names separately? The answer is no, we merge them into a class called race, and the design becomes the following again:
Create a factory class
See here, we may think: Now the structure seems to be very perfect, we have defined the interface to solve the problem, and do not create many different classes for different roles, and as long as the race in the constructor to represent the body parts of the variables to assign different values, you can create different races of characters. OK, then let's see if you want to create a human code that needs to be written:
Head head = new Humanhead ();
Stature stature = new humanstature ();
Skin skin = new Humanskin ();
Race human = new Race (head, stature, skin);
And the race constructor is this:
Public Race (head, stature, skin) {
This.head = head;
This.stature = stature;
This.skin = skin;
}
We see that it seems too troublesome to just create a class, and that part of the body class is part of the role, why do they have to be created before the role?
At this point, we thought that if there was a class that could be dedicated to creating body parts, when we wanted to create a character, we would pass the class to the race constructor. The class in which we create human body components is called: Humanpartsfactory, the class that creates the Elf body part is called Elfpartsfacotry. So that's what they should be like:
Now, we're going to create a human, and the code becomes this:
Humanpartsfactory humanfactory = new Humanpartsfactory ();
Race Human = new Race (humanfactory);
Accordingly, our constructors also need to be changed:
Public Race (Humanpartsfactory humanfacotry) {
Head = Humanfactory.createhead ();
stature = Humanfactory.createstature ();
Skin = Humanfactory.createskin ();
}
Everything seems to be fine until we need to create an elf ... We find that the race constructor can only accept parameters of a humanpartsfactory type, and in order to pass the elfpartsfactory we will have to add a constructor that accepts the Elfpartsfactory type. This is obviously not good, this time, with the previous experience, we know that we can be solved by the same method.
See here, can you appreciate some of the "interface-oriented" programming implications? Notice that the Racepartsfactory method internally returns the interface type, and the method of its entity subclass returns the entity class of the interface. If we had not declared the seemingly useless interface before, this would not be possible.
Now, let's modify the race constructor again:
Public Race (Racepartsfactory racefacotry) {
Head = Racefacotry.createhead ();
stature = Racefacotry.createstature ();
Skin = Racefacotry.createskin ();
}
When we need a human:
Racepartsfactory humanfactory = new Humanpartsfactory ();
Race human = new Race (humanfactory);
When we need an elf:
Racepartsfactory elffactory = new Elfpartsfactory ();
Race elf = new Race (elffactory);
Abstract Factory Design Pattern
The above, which led to the completion of a design pattern: Abstract Factory. Its formal definition is this: provide an interface for creating a series of interrelated or interdependent objects without specifying their entity classes.
The following is the final diagram of the Abstract factory pattern in this example:
Code implementation and testing
Using System;
Using System.Collections.Generic;
Using System.Text;
Namespace Abstractfactory {
Define the interface that makes up the body part
Public interface Ihead {string name {get;}}
Public interface Istature {string name {get;}}
Public interface Iskin {string name {get;}}
Classes that make up Human
public class Humanhead:ihead {public string name {get {return ' Human Head ';}}}
public class Humanstature:istature {public string name {get {return ' Human stature ";}}}
public class Humanskin:iskin {public string name {get {return ' Human Skin ';}}}
Classes that make up the ELF
public class Elfhead:ihead {public string name {get {return ' Elf Head ';}}}
public class Elfstature:istature {public string name {get {return ' Elf stature ';}}}
public class Elfskin:iskin {public string name {get {return ' Elf Skin ';}}}
Defining the Factory interface
Public interface Iracepartsfactory {
Ihead Createhead ();
Iskin Createskin ();
Istature createstature ();
}
Define the factory class of the human body
public class Humanpartsfactory:iracepartsfactory {
Public Ihead Createhead () {
return new Humanhead ();
}
Public Istature createstature () {
return new Humanstature ();
}
Public Iskin Createskin () {
return new Humanskin ();
}
}
Define the ELF body's factory class
public class Elfpartsfactory:iracepartsfactory {
Public Ihead Createhead () {
return new Elfhead ();
}
Public Istature createstature () {
return new Elfstature ();
}
Public Iskin Createskin () {
return new Elfskin ();
}
}
Defining the Race Class
public class Race {
Public Ihead Head; For demonstration purposes, so no build properties
Public istature stature;
Public Iskin Skin;
Public Race (Iracepartsfactory racefactory) {
Head = Racefactory.createhead ();
stature = Racefactory.createstature ();
Skin = Racefactory.createskin ();
}
}
Class Program {
static void Main (string[] args) {
Create an Elf (ELF)
Race ELF = new Race (new Elfpartsfactory ());
Console.WriteLine (Elf.Head.name);
Console.WriteLine (Elf.Stature.name);
Console.WriteLine (Elf.Skin.name);
}
}
}
Summarize
In this paper, we learn the Abstraction Factory Abstract Factory mode.
I begin by introducing one of the problems our fantasy RPG faces: We need to create roles of different shapes. Subsequently, we completed the process through an implementation-oriented approach, and discussed its shortcomings. Then we first abstracted the race through the use of the interface. Next, we encapsulate the process of creating the role component class, delegating the process to the factory class. Finally, we abstracted the factory class and finally realized the abstract factory factory model.
I hope this article will bring you help.
Copyright NOTICE: This article for Bo Master original article, without Bo Master permission not reproduced.
Fantasy RPG (character structure and Abstract Factory mode)