Today's refactoring has no fixed form. I have used different versions over the years, and I bet different people will have different versions. This refactoring applies to scenarios where the switch statement block is large and new judgment conditions are introduced at any time. In this case, we recommend that you use the policy mode to encapsulate each condition into a separate class. There are many ways to implement the rule mode. The policy refactoring I introduced here uses a dictionary policy. The advantage of this is that the caller does not have to modify the original Code .
Today's refactoring has no fixed form. I have used different versions over the years, and I bet different people will have different versions. This refactoring applies to scenarios where the switch statement block is large and new judgment conditions are introduced at any time. In this case, we recommend that you use the policy mode to encapsulate each condition into a separate class. There are many ways to implement the rule mode. The policy refactoring I introduced here uses a dictionary policy. The advantage of this is that the caller does not have to modify the original code.
namespace lostechies. daysofrefactoring. switchtostrategy. before {public class clientcode {public decimal calculateshipping () {shippinginfo = new shippinginfo (); Return shippinginfo. calculateshippingamount (state. alaska) ;}} public Enum state {Alaska, NewYork, Florida} public class shippinginfo {public decimal calculateshippingamount (State shiptostate) {Switch (shiptostate) {Case state. alaska: Return getalaskashippingamount (); Case state. newYork: Return getnewyorkshippingamount (); Case state. florida: Return getfloridashippingamount (); default: Return 0 m;} private decimal getalaskashippingamount () {return 15 m;} private decimal getnewyorkshippingamount () {return 10 m ;} private decimal getfloridashippingamount () {return 3 m ;}}
To apply the refactoring, you need to separate each test condition into a single class, which implements a common interface. Then, use enumeration as the dictionary key to obtain the correct implementation and execute its code. If you want to add new conditions in the future, you only need to add a new implementation class and add it to the shippingcalculations dictionary. As mentioned above, this is not the only way to implement the policy mode. I will show the font in bold here because someone will definitely point this out in the comments :) use the method you think is useful. The advantage of implementing refactoring in this way is that you do not need to modify the client code. All modifications are made within the shippinginfo class. Jayme Davis pointed out that this refactoring still needs to be bound in the constructor, so it only adds some classes. However, if the policy of binding ishippingcalculation can be placed in IOC, there are still many benefits. It allows you to bind policies more flexibly.
Namespace lostechies. daysofrefactoring. switchtostrategy. after {public class clientcode {public decimal calculateshipping () {shippinginfo = new shippinginfo (); Return shippinginfo. calculateshippingamount (state. alaska) ;}} public Enum state {Alaska, NewYork, Florida} public class shippinginfo {private idictionary <state, ishippingcalculation> shippingcalculations {Get; set;} public shippinginfo () {shippingcalculations = new dictionary <state, ishippingcalculation> {state. alaska, new alaskshippingcalculation ()}, {state. newYork, new newyorkshippingcalculation ()}, {state. florida, New floridashippingcalculation () };} public decimal calculateshippingamount (State shiptostate) {return shippingcalculations [shiptostate]. calculate () ;}} public interface ishippingcalculation {decimal calculate ();} public class alaskshippingcalculation: ishippingcalculation {public decimal calculate () {return 15 m ;}} public class newyorkshippingcalculation: ishippingcalculation {public decimal calculate () {return 10 m ;}} public class floridashippingcalculation: ishippingcalculation {public decimal calculate () {return 3 m ;}}}
To make this example complete, let's look at how to bind ninject to the IOC container in the shippinginfo constructor. Yes
There are many changes, mainly by placing the State enumeration inside the policy, and passing an ishippinginfo
Ienumerable generic. Next we will use the state attribute in the Policy class to create a dictionary, and the rest will remain unchanged. (Thanks to Nate kohari.
And jayme Davis)
Public interface ishippinginfo {decimal calculateshippingamount (State state);} public class clientcode {[inject] public ishippinginfo shippinginfo {Get; set;} public decimal calculateshipping () {return shippinginfo. calculateshippingamount (state. alaska) ;}} public Enum state {Alaska, NewYork, Florida} public class shippinginfo: ishippinginfo {private idictionary <state, ishippingcalculation> shippingcalculations {Get; set ;} public shippinginfo (ienumerable <ishippingcalculation> shippingcalculations) {shippingcalculations = shippingcalculations. todictionary (calc => Calc. state);} public decimal calculateshippingamount (State shiptostate) {return shippingcalculations [shiptostate]. calculate () ;}} public interface ishippingcalculation {state {Get;} decimal calculate ();} public class alaskshippingcalculation: ishippingcalculation {public state {get {return state. alaska ;}} public decimal calculate () {return 15 m ;}} public class newyorkshippingcalculation: ishippingcalculation {public state {get {return state. newYork ;}} public decimal calculate () {return 10 m ;}} public class floridashippingcalculation: ishippingcalculation {public state {get {return state. florida ;}} public decimal calculate () {return 3 m ;}}