Online ghost Game Development 2: Ghost Game Development
"Memories are always cruel"-in "design business objects and object division of duties (2)", I analyzed the old version of code and found a lot of bad smell, this article will record how I build the division of duties for new business objects.
I. Review the design model
The original path of the self-taught design model was: from the "big talk Design Model" (taking notes) to the "Design Model" of Gof. go to the summary logs of the hard-working netizens (only reading C # may have some limitations ~). After that, whenever I need to update the code or do not remember the 23 classic design patterns, I will go back to my notes, mainly looking: mode purpose and application scenario, which can be played back in mind as quickly as possible. During the review, you may unconsciously think that this design pattern may solve some problems in the project to be updated, and then immediately read the code analysis in article (2, I also made a simple uml class diagram design on the draft board (I bought a whiteboard as a draft paper) and passed the sample code in my mind. In my opinion, this practice should be repeated until skillful.
When I wrote this article, I felt it was necessary to share a note to summarize the part of the design pattern in one sentence in 23, so I wrote: The Design Pattern in one sentence, I believe it must be a bit full of Slot :)
After review, I initially thought that the following modes may be used:
Creation type: Single Instance (Setting), Candidate: factory;
Structural: decoration (handling the structural relationship between roles), candidates: Bridging and proxy;
Behavior Type: Observer (regular update), intermediary (played by Game as the intermediary of each participant), status (dead state changes, may be overly designed), Candidate: visitor;
2. Optimize the game process
(1) Old Version: after entering, there will be a button to watch/register for the login to choose from, the Table class is responsible for maintaining the list of all people, and will change the class continuously when you exit the watch/register;
Optimization: after entering the system, the observer does not need to do anything. Instead, the applicant needs to click the "Seat" button, which is more realistic; the Table class no longer maintains the bystander list-because the Table game Table only needs to care who participates in the game, and the name of the spectator does not contribute in the whole game process; no new classes will be generated before the game starts (that is, registration and watching), because the identities of civilians, idiots, and ghosts should be generated only after the game starts, rather than starting from the beginning, this approach also avoids the complex conversions between classes in article (2.
(2) Old Version: the vote is not completed
Optimization: AddBallot () adds the vote-IsVoteEnd () indicates whether the vote ends-Roll () singing, three parts. That is, when a participant selects the person to vote or disauthorizes the vote, the voting Manager checks whether the vote is over. If the vote is not over, the voting manager continues to receive the vote. If the vote is over, start singing. Good understanding ~
Iii. Division of object responsibilities and object collaboration Sequence
Presumably, this is the most important part of this series. In the subsequent code implementation process, we will continue to review this section, and even find that this section can be further optimized and updated.
This section uses UML2.0 as the notation and uses the Rational Rose tool fromClass Diagram and sequence diagramThis section describes the relationships between key business classes and how these classes distribute messages and collaborate to complete tasks in mainstream game processes.
(1) first look at the class chart
Class digoal
Not Complicated. Some associations are also omitted. (For example, Ghost can be directly associated with SpeakManager and VoteManager to solve the first round of discussion in the Ghost program ), show only the main relationship. Let's start with the class in the old version:
Seven classes in the old version: Table, Game, Subject, Setting, Audience, Civilian, and Ghost. All the classes except Audience are written.
Follow the game order:
Table:It is a Game table class created in singleton mode when a Game program is started. A Game class and PlayerManager class are maintained internally.
Why is there no way? Of course there are some, but they are in the preliminary design phase. As mentioned above, these class diagrams, sequence diagrams, and even game flows may find unreasonable points in subsequent code implementations, modify it later (I will also go back to the relevant article to modify it, and write a log for this series-to record key modification behaviors ).
PlayerManager:One of the bad smell of the old Table class is that it has too many responsibilities, not only to inform the Game class to start the Game, but also to maintain the number of desktop users and check whether the Game starts, the unnecessary responsibilities are separated and the PlayerManager class with dedicated maintenance personnel is created. The method is to Set, Delete, and Get the Player. The key attribute is to maintain a String array of nine members, NameArray, which is responsible for determining the list of seat holders before the game starts, so as to list the order. After the game starts and assigns roles, it maintains the Player array and PlayerArray of 9 members. Why use Array instead of the List in the old version? Because the number of standard users has been set up (which can be maintained in xml. Here, the standard number is used). Only the corresponding seat is used and the memory is less required, the computing speed between classes is faster and easier to store.
Setting: The only difference from the old version is that Setting is responsible for checking whether the person in the seat registration is full (), returning the Boolean value type and reporting back to the Table all the way, the Table sends a Start () notification to the Game.
Game: A lot of original responsibilities have been assigned, so it's okay ~ Hey! Indeed, after assigning responsibilities, only Start () is left, and Start Restart () again-end a game and Start a new game, of course, you can also create a new Game object by using Table, which makes it easier to create a Game ~ Now, let's take a look at the door with a pipe in your mouth. Happy to look at the work of the younger brother at the bottom of the house. Just give me the command to start and receive the work. Oh, yes, I don't even need to say it when I receive the work, the younger brother will determine whether the game is over.
Subject: The only difference from the old version is that Subject is responsible for obtaining the question GetSubject () from the dictionary, and filling in the attributes of the three words maintained by itself. In the future, the outside world will require words, they all look for him (in the old version, we copied a copy to each participant, and the new approach seems to be different from the reality, but it is actually the advantage of the informationization process that may be used to manually modify questions and cheat). Therefore, we need to establish a global access point, so we still need to consider creating the singleton mode.
Player, Civilian, Idiot, and Ghost:The latter three inherit from the Player, and the Player array maintained by PlayerManager is an abstract class Player. If you need to propose a specified class of objects, you can consider using lambda expressions, for example, List <Ghost> ghostList = PlayerManager. player. toList (). where (g => g. type (). equals (Ghost); -- it has not been directly played in vs. Please forgive me for any bugs. [Xiao]! In the old version, Ghost inherits from Civilian and Civilian inherits from Audience. In this example, the observer class is not considered. (This Audience class may be added in the code implementation section, and Ghost is not actually a Civilian. Therefore, we should not use inheritance relationships to indicate that all their similar methods should be upgraded to the Player abstract class, as mentioned in the design model, non-is-a relationships should not be represented by inheritance relationships. How can we differentiate Civilian, Idiot, and Ghost? Don't forget that the decoration mode can dynamically add additional responsibilities or labels to the encapsulated objects ~ (Review section 1 of this article to review the design patterns that may be used)
All right, the rest of the classes are separated from the old Game:
RoleManagerAssign roles,SpeakManagerResponsible for managing the dialog list,LoopManagerChecks whether the current round of speeches (including the speeches at PK time) are complete,VoteManagerManages the voting process,DeathManagerResponsible for serving as executors,WinManagerChecks whether the ghost wins (the ghost continues without victory until the ghost is completely killed or the ghost wins, so there is no need to take the victory of good people as the standard to end the game ).
Okay, so all classes are dedicated to taking charge of what they want to do-a single responsibility principle-How nice if there is such a single responsibility in real life, however, the society needs all talents, just like the leaders who want to learn computer science are also called to move the mailbox (metaphor, metaphor ~), I have also had four years of work experience on the job topic. I am afraid to make a shift in front of all the elders and give me some things that have little experience or knowledge. I am still a young man and never wake up with my dream, do what you can afford ~
(2) sequence of entry and game start
Enter digoal
What is a sequence chart? I believe that even friends I don't know can understand it.
1-4. When someone is seated, the Table will give this nickname to PlayerManager. The PlayerManager asks Setting "Are there any people ?" (IsFull ()). When someone stands up, it also tells PlayerManager to delete the person's name. At this time, PlayerManager maintains a String array. If Setting tells PlayerManager "everyone !", The message will be sent back to the ears of the Table. The Table pulls out a monkey hair and blows it. (As a painter, you must pay tribute to the Ignited Chinese-made animation "Return of the Holy Child !), The Game starts.
5-6. Game first asks the Subject for a question, then calls RoleManager to randomly assign a role to the String array maintained by PlayerManager, and puts the role on the Player abstract class in sequence, and then queues it back to PlayerManager. Does RoleManager seem a bit like a leader in the builder mode-You dare to bring only one talent (class method), and you will not take a cloud color when you rush to complete the task as required. Haha, it means that whether the builder mode can be combined with the builder mode and whether it is necessary to combine the builder mode can be discussed with you in the code implementation section.
7-8. After the questions and identity roles are ready, the system will talk about them and explain their respective identities and questions to the Player contestants. It also shows the first round of speaker designated by the ghost. The SpeakManager deserves to be the completer of this task. It displays the SystemSpeak () that the system says, And then publishes the record to the front-end ShowRecord ().
(3) ghost discussion sequence diagramGhost Speak digoal
Very simple. It is enough to find the SpeakManager ~
(4) ghost voting (determining the first round of spokespersons)
Ghost Vote digoal
1-3. when the ghost vote decides the first round of the spokesman, the front-end interface will display a button for everyone's name (the String name array maintained by PlayerManager can be used again ), every time a Ghost clicks to vote, the Ghost object delivers the ticket to the vote checking officer VoteManager. The ticket checking officer will check if all of them have been voted out, IsVoteEnd (), and Roll ().
4-5. it belongs to the alternative event stream (from the reference of RUP, the event stream is divided into the main event stream and the alternative event stream). It occurs when the ghost voting results are inconsistent (Some people press the wrong button or their opinions are inconsistent, at this time, the ticket checking officer VoteManager will ask the SpeakManager to release the holy theme SystemSpeak (), tell the front-end ShowRecord (), and let the ghosts unify their opinions and vote again.
6-7. when the vote of a ghost is the same, the ticket checking officer is relieved and quickly handed over the baton to LoopManager to record the beginning of this round, then let the SpeakManager set the first round of speaker for the speaker. What is "allowed to speak"? If a player who is not officially allowed by the SpeakManager to speak with SetSpeaker (), no matter what they say, it will not be recorded, of course, ShowRecord () will not be shown to others, that is to say, the role of "who is allowed to speak" must be put on the SpeakManager.
(5) diagram of the speech sequence of all gamers
Player Speak dimo-
Unlike the ghost speech, the player speech should be in order, and after each speaker, LoopManager will take a look at whether the current round is over. I will not go into details about the specific process.
(6) voting sequence of all players
Player Vote digoal
1-5. Normal voting, not repeated.
6-7. It is an alternative event stream used for PK speech when the voting result shows the same number of votes. It shows that the voting officer handed the same vote to LoopManager and asked him to decide who should first talk about SetLoopStarter (). Don't forget to tell SpeakManager to allow him to record his words SetSpeaker (). After that, he will return to Step 1-5, continue voting. Of course, as described in the introduction to the game process in the series, people on PK platforms cannot vote on their own, which is not shown in the sequence diagram, in actual code, it can be identified by whether the Player has the right to vote (temporarily deprive the voting right of the rule of law ).
8-9. in any case, at the end of each round, someone must be handed over to DeathManager, the vote-checking officer, and the death penalty is executed by SetPlayerDie () -- In the old version, the gamer commits suicide (the SetDie method is included in the Player Object). In the new version, the executors are executed. It feels more reasonable ~ Every time someone rises to the next day, WinManager will show off his head to see if the Game (Table. Game) is over. The final standard is whether the ghost wins IsGhostWin ().
10-11. if the game is not over, the baton of the game will return to VoteManager again (after all, it is a series of interactions in the voting process, making it inappropriate for any other Manager to access the baton ), the ticket checking officer will notify LoopManager to start a new round of players' speeches. Of course, do not forget the SetSpeaker () allowed by the SpeakManager to make the speech free ~
Iv. Summary of this step
At the end of this article, I would like to add a section to describe the above-mentioned (I think it is more clear) Class responsibility division and process, it is how the old version of thinking is built in a subtle manner. First:
In order to let everyone see the notes, I will not scale down.
This is the first figure I considered during the design. We can see that in the upper left corner, we still use the three-layer inheritance method to process each role. Because we didn't figure it out at the moment, we don't want to get stuck in this step, the roles of Table and Game are separated. In the lower left corner, the original PlayerManager is just a child (PlayerList, an attribute). It targets the Player abstract class inherited from Audience (but it still does not solve the issue of layer-3 inheritance, and deep-rooted Audience thinking ). As shown in the figure, the Game assigned the roles and responsibilities to the new employees, their original names were Roler, Speaker, LoopChecker, Voter, WinChecker, Death, and StartChecker (finally, through the Responsibility Analysis, they should be allocated to Setting to get their current nickname IsFull () from now on ......). The general sequence of each class can be viewed in the serial number 1-13 on the right of the graph. A friend at the eye may see the logic for judging Y/N. Haha ~
This second picture is designed to solve the problem of the relationship between roles. We can see that the PlayerManager class has been created at this time, and it is in the same level as the Game class and managed by the Table Eldest Brother. The messy notes in the figure are traces of the tangle of thoughts in the days of the city. The careful readers may see the enumeration Role: Enum. Yes, I wanted the Player class to inherit from the Audience class, in this way, three layers are inherited as two layers, and all roles are distinguished by Enumeration type Role attributes. However, due to the open and closed principle (to expand and open, to modify and close ), does not apply to the increase of enumeration. For example, if a game is upgraded one day and the Huawei role is added to the rule, the game can resume life (a bit like an upgraded version of a killer game ), do I have to go to enumeration for modification? Why not add a new class, so there is a box in the Person class in the figure, and other roles inherit from Person -- yes, in this case, we will not return to the layer-3 inheritance of the old version? No, although the problem of multi-level inheritance has not been solved, at least one important problem has been solved:Non-is-a relationships cannot be inherited.-- Civilian and Ghost are no longer inherited! This is too important. Please remember, if it is only for convenient method calling, it can be solved through the template mode, and no proxy or appearance mode can be achieved, if the inheritance relationship is less than an "is-a" link, do not consider it. Otherwise, there may be a huge inheritance tree problem, or, as in the old version, frequent conversion of parent and child classes is not conducive to adding additional responsibilities or labels (methods or attributes) to a link in the inheritance tree ).
Those with strong observation may have noticed the gamer seat chart made around the table in the upper right corner. Yes, at that time, I thought that the front-end interface should not only be slightly optimized, but also solve the Audience class problem. In this case, I came up with the "Round-Table Meeting + sit-down button" method like Texas hold'em, in this way, the button for registration/observation is replaced. Thanks to paid poker, I suddenly felt that Audience and others did not really contribute much to the game. As if you are going to the Macau casino, you may only care about the psychology of the opponents competing at the same table, but not the onlookers standing at the round table. (do not fill in the cheating onlookers ~), You don't even want to know the name of a bystander. You just need to know the approximate number of people around you. (You can use cookies to calculate the number and do not need to update it immediately, a fixed period of time does not affect updates, but can also save traffic ).
Therefore, I think the interface should be laid out a little more, and the main order in the first draft is straightened out. Therefore, the third figure is displayed:
Haha, I see the picture at first glance. It seems that there is no difference except for listing the Round Tables. Okay ...... I admit it is.
The information flow arrows in the sequence diagram are shown in braces and arrows on the right. Is it possible to find that the process is rough or even the whole process (Sequence Chart) is so large? How can we solve it in a few lines? When I draw the third image, I think the idea of chaos has been opened up, the division of duties, process optimization, object relationships, and other major issues have been solved, and only a well-planned list of world-class drawings is left. That is, the sketch sorting process has been broken, you can go to the process of summarizing ideas and organizing documents, and then I will transfer to the above three types of diagrams and sequence diagrams.
If you have to ask what representations are used for the above three graphs, then I can only shoot my head and get a meaningless name-not limited to drawing tools (rational rose, visio, or vs modeling projects) in my hands ), in the first place, it was impossible to show the brain waves jumping and waiting for confusion in such a well-organized computer software.On the draft paper, frame line, rough mark, write down what you want as quickly as possibleDon't forget that software is also advanced for humans. Believe in your brain and pen-holding hands!
If you want to explain the sequence, refer to the RUP (unified software development process) to learn more about OOAD (Object-Oriented Analysis and Design ), combined with the SOLID principle (single responsibility, open and closed, Lee's replacement, interface isolation, dependency reversal), the entire design and code writing process is constantly evolving.IterationExamine and finally achieve perfect-I can't help but think of one of my senior sketch teachers, Zhao Jin and Zhao, who love painting. He spent many years painting which depicts the life of peasants under the big banyan tree, I am glad to add a few more phishing scams next year's eve ......
Coder, come on, we still have to do a lot of things, even if we are not on the technical road, we can make friends, see attitude from the code, understand the world,Don't waste money on the road to IT..
PS: readers may wonder how the design results do not reflect the specific design model? Because the author considers that the design mode cannot leave the code, and the design mode is the idea, the advice, rather than the ultimate goal. It can be considered and considered in the design process, it is better to write down the connotation and essence of code implementation, and even mode deformation than to fall into excessive design.