Bookstore Member Sales System (2)
--Oo, Refactoring and Design Pattern This program: 1. Learn the use of strategy mode. 2. Use reconstruction techniques. Customer: "I think your discount algorithm is a bit problem." Project Manager: "What is the problem? Customers:" In this algorithm, customers should consume at least 1,000 yuan to enjoy discounts, I want to take different books, take different Discount algorithm, you need to let me set a discount algorithm. "Project Manager:" You are more reasonable, we will modify the procedure to meet your requirements. "Customer:" The next version gives me this feature? "Project Manager:" There is no problem. "I heard this dialogue, we can know that the new feature we need to add is to configure the discount algorithm, but before implementation, let us first put on the" reconstruction "hat. In the cmember member class, according to the cumulative points Discount this feature is very unstable, we should refine it into a class. Crebaterule (); ~ crebaterule (); float calcrebate (int npoint);}; float crebaterue :: Calcrebate INT nPoint) {IF (Npoint <= 100) Return 10; Else IF (Npoint> 100 && Npoint <200) Return 9.5; Else IF (npoint> = 200 && Npoint <400) Return 9; Else IF (npoint> = 400 && npoint <600) Return 8.5; Else Return 8.0; Does the customer do not configure their own discount algorithm? We can write the discipline in the configuration file, then read into the data structure, which is more flexible. Now is a hat, wear "reconstruction" Add a new feature, add a function to the CrebaterUle class. Bool crebaterule :: init (char * pszconfigfilename) {// Read the discount algorithm from the configuration file, I will not write here. Return True;} FLOAT CREBATERULE :: CALCREBATE (INT NPOINT) {// For convenience, it is assumed that this is read from the configuration file.
IF (Npoint <= 100) Return 10; Else IF (Npoint> 100 && Npoint <200) Return 9.5; Else IF (Npoint> = 200 && Npoint <400) Return 9; Else IF (Npoint> = 400 && Npoint <600 ) RETURN 8.5; Else Return 8.0;} Modify cmember :: getRebate () function: float cmember :: getRebate () {create ("configfile.txt"); return rebatelule.calcrebate (m_npoint);} The program is tested. However, after a while, the customer started to complain: "I want to achieve folding features in some holidays, and now the programs are still not implemented." To now, the policy mode will be played, but before the new features We still have to consider it, ask yourself a question: "Now I add this function, do you need to change some of the original class?" Answer is affirmative. Then we wear a "reconstruction" hat. Carefully observe the CCalculate class, two of which are the number of points of the accumulated member, one is based on the discount of the members to calculate the amount of consumption, I think we can move them to the CMEMBER class will be better.
First modify main function: int main (int Argc, char * argv []) {char szmemberid [MAX_PATH]; STRCPY (SZMEMBERID, "00000001"); float fconsumesum = 120.0; int npoint = 0; cmember * pmember = new cmember szMemberID, 1000.0,75); nPoint = pMember-> GetPoint (); nPoint = pMember-> CalculatePoint (fConsumeSum); fConsumeSum = pMember-> CalcMoney (fConsumeSum); pMember-> SetPoint (nPoint); assert (nPoint == 87); assert (fconsumesum == 120.0); Printf ("POINT =% D / N", NPOINT); Printf ("consumesum =% f / n", fconsumesum); delete pmember; return 0;} and CMEMBER Two functions: int cmember :: calculatepoint (float fsum) {int npoint = (int); return npoint;} float cmember :: calcmoney (float fsum) {float frebateSum = 0.0; frebateSum = fsum * GetRebate () / 10; Return FrebateSum;} Compiler, by testing. Let's analyze it again, whether the CalculatePoint function is open to the way, we can completely accumulate points when calculating the discount amount. So the main function we can modify it. int main (int argc, char * argv []) {char szMemberID [MAX_PATH]; strcpy (szMemberID, "00000001"); float fConsumeSum = 120.0; CMember * pMember = new CMember (szMemberID, 1000.0,75); fConsumeSum = pMember -> Calcmoney (fconsumesum); Assert (pmember-> getPoint () == 87); assert (fconsumesum == 120.0); Printf ("Point =% D / N", nPoint); Printf ("consumesum =% f / n ", fconsumesum); delete pmember; return 0;} Modify CMEMEMBER :: CalculatePoint is a private function. Modify the CMEMBER :: Calcmoney function.
FLOAT CMEMBER :: Calcmoney (FLOAT FSUM) {FLOAT FREBATESUM = 0.0; FreBateSum = fsum * getRebate () / 10; CalculatePoint (fsum); Return FrebateSum;} Compiler pass, you can debug. The reason is simple to check, it is CMEMBER :: CalculatePoint, has not been modified correctly. After modification: int cmember :: calculatepoint (float fsum) {m_npoint = m_npoint (int) (fsum / 10); return m_npoint;} Compiler, through testing. CMEMBER :: CalculatePoint also needs to return parameters? Change to Void. Don't forget to compile test, guarantee a small step each time, we can also go to the Yellow River. Think about it, is the name of Calcmoney? RebateSumAndcumulatePoint may be more better. The above reconstruction is not to add new functions, just for the program more concise, more readable. The following reconstruction begins to do in order to add new features. The UML diagram is as follows: Remind the existing CrebaterUle to CNORMALREBATERULE, and then modify the program to make it test. Create a new abstract class CrebaterUle. Class CrebaterUle {public: Virtual ~ crebaterule (); Virtual Bool Init (Char * pszconfigfilename) = 0; Virtual float calcrebate (int npoint) = 0;}; According to the design, we continue to modify the program so that it is compiled. So far, we can add new features. This way we add CSPecialRebaterUle classes, and existing classes do not need to be modified, wear "Add new features" hat. We first regulate 50% off.
To write main function: int main (int argc, char * argv []) {char szMemberID [MAX_PATH]; strcpy (szMemberID, "00000001"); float fConsumeSum = 120.0; CMember * pMember = new CMember (szMemberID, 1000.0,75 ); CRebateRule * pRebateRule = new CNormalRebateRule; pRebateRule-> Init ( "Configfile.txt"); fConsumeSum = pMember-> RebateSumAndCumulatePoint (fConsumeSum, pRebateRule); assert (pMember-> GetPoint () == 87); assert (fConsumeSum = = 120.0); Printf ("POINT =% D / N", Pmember-> getPoint (); Printf ("consumesum =% f / n", fconsumesum); delete prebaterule; prebaterule = new cspecialRebaterule; prebaterule-> init "Configfile.txt"); fconsumesum = Pmember-> RebateSumandcumulatepoint (300.0, prebaterule); assert (pmember-> getPoint () == 117); assert (fconsumesum == 270.0); printf ("Point =% d / n" , Pmember-> getPoint ()); Printf ("consumesum =% f / n", f / n ", fconsumesum); delete prebater; relete 0;} Add the cspecialrebaterule class and function, I will not write the code here. You can download the code. FLOAT CSPECIALREBATERULE :: CalcRebate (int npoint) {// assumes that users have enjoyed a discount of 9.5 fold. Return (9.5 * 9.0 / 10);} Compiler, by testing. Maybe someone will ask, why don't you use Factory Method design mode? Here, the discount algorithm is used here, not the use of the log class, after all, using Factory Method will introduce the Factory class, increase the complexity of the program, when we do not use, we still avoid use, simple You can use Simple Factory to replace. Remember: Don't add new features at the beginning, but through the reconstruction technique, do not change the original function of the software, step by step, so that it is suitable for the new features. Ok, it's more comparable to it, but this is a programming process. Written using C language, commissioning at VC 6.0 environment.