• Refactoring Part 7: Replacing conditional with polymorphism

    This is the last and biggest in this refactoring series. For more great information about refactoring please pick up Martin Fowler's: Refactoring: Improving the Design of Existing Code

     

    According to fowler, we shouldn’t be using a switch statement on something else’s data, but only when it’s our own data. I would say this is also applicable to if/elseif conditionals as well in some cases.

     

    The relevant code is the Charge property.

     

     

            public double Charge

            {

                get

                {

     

                    double result = 0;

                    switch (Movie.PriceCode)

                    {

                        case Movie.REGULAR:

                            result += 2;

                            if (DaysRented > 2)

                            {

                                result += (DaysRented - 2) * 1.5;

                            }

                            break;

                        case Movie.NEW_RELEASE:

                            result += DaysRented * 3;

                            break;

                        case Movie.CHILDRENS:

                            result += 1.5;

                            if (DaysRented > 3)

                            {

                                result += (DaysRented - 3) * 1.5;

                            }

                            break;

                    }

                    return result;

                }

            }

     

    His first step was to move the logic of getCharge() into the movie conditional.  This changes the property to look like this:

           public double Charge

            {

                get

                {

                    return Movie.GetCharge(DaysRented);

                }

            }

    And the code that moved into Movie to look like this:

            public double GetCharge(int daysRented)

            {

                double result = 0;

                switch (PriceCode)

                {

                    case Movie.REGULAR:

                        result += 2;

                        if (daysRented > 2)

                        {

                            result += (daysRented - 2) * 1.5;

                        }

                        break;

                    case Movie.NEW_RELEASE:

                        result += daysRented * 3;

                        break;

                    case Movie.CHILDRENS:

                        result += 1.5;

                        if (daysRented > 3)

                        {

                            result += (daysRented - 3) * 1.5;

                        }

                        break;

                }

                return result;

            }

     

    Wait, there’s data being used from both objects! Of course fowler is onto that and suggests the reason to move it here is because the data that is most likely to change is the movie types “Regular, New Release, Children’s…” and changes to this will have the least ripple effect if changed now that it exists inside the Movie class. 

     

    Now we should do the same thing with frequent renter points so that the movie type is ‘being worried about’ in the same class.

     

    Inside rental:

            public int FrequentRenterPoints

            {

                get

                {

                    return Movie.getFrequentRenterPoints(DaysRented);

                }

            }

     

    Inside Movie:

            public int getFrequentRenterPoints(int DaysRented)

            {

                if ((PriceCode == Movie.NEW_RELEASE) && DaysRented > 1)

                {

                    return 2;

                }

                else

                {

                    return 1;

                }

            }

     

    I’m noticing fowler does a great job of ensuring we don’t leave any method callers stranded by pointing old properties at the new code. Sometimes, you may have to remove something, just be sure you’re going back and updating all references to it to point to the new logic.

     

    Now, we’re ready to use polymorphism, right? We can just have a class for each type of movie… NOPE. Unfortunately, we can’t because our type can change at runtime. Fowler suggests using a state pattern. Basically our PriceCode will be come a Price Object… and we’ll have a Price Object for each of the types of prices.

     

    To introduce the state code, Fowler says we’ll be doing 3 refactorings: “Replace type code with State/Strategy” to move the price behavior into a state, “Move Method” to move the Price property into the price class, and then “Replace conditional with Polymorphism” to eliminate the switch.

     

    He says the first step in moving the type code to a state is to ensure all setting of the state is done through the setter (or property in .Net).

     

    Therefore our constructor:

            public Movie(string title, int priceCode)

            {

                _title = title;

                _priceCode = priceCode;

            }

     

    Becomes:

            public Movie(string title, int priceCode)

            {

                _title = title;

                PriceCode = priceCode;

            }

     

    Now we add the new classes:

        public abstract class Price

        {

            public abstract int PriceCode{get;}

        }

        public class ChildrensPrice : Price

        {

            public override int PriceCode

            {

                get

                {

                    return Movie.CHILDRENS;

                }

            }

        }

        public class NewReleasePrice : Price

        {

            public override int PriceCode

            {

                get { return Movie.NEW_RELEASE; }

            }

        }

     

        public class RegularPrice : Price

        {

            public override int PriceCode

            {

                get { return Movie.REGULAR; }

            }

        }

    Compile and check… everything runs good still. Excellent.

    Now we have to change the Movie’s accessors to use the new class.

     

    Before:

    private int _priceCode;

            public int PriceCode

            {

                get { return _priceCode; }

                set { _priceCode = value; }

            }

           

    After:

            private Price _priceCode;

            public int PriceCode

            {

                get { return _priceCode.PriceCode; }

                set

                {

                    switch (value)

                    {

                        case Movie.REGULAR:

                            _priceCode = new RegularPrice();

                            break;

                        case Movie.CHILDRENS:

                            _priceCode = new ChildrensPrice();

                            break;

                        case Movie.NEW_RELEASE:

                            _priceCode = new NewReleasePrice();

                            break;

                        default:

                            throw new ArgumentException("Incorrect price code");

                    }

                }

            }

     

    And now we can apply the “Move Method” to the get charge (Charge Property)

     

    Before:

            public double GetCharge(int daysRented)

            {

                double result = 0;

                switch (PriceCode)

                {

                    case Movie.REGULAR:

                        result += 2;

                        if (daysRented > 2)

                        {

                            result += (daysRented - 2) * 1.5;

                        }

                        break;

                    case Movie.NEW_RELEASE:

                        result += daysRented * 3;

                        break;

                    case Movie.CHILDRENS:

                        result += 1.5;

                        if (daysRented > 3)

                        {

                            result += (daysRented - 3) * 1.5;

                        }

                        break;

                }

                return result;

            }

     

    After:

           public double GetCharge(int daysRented)

            {

                return _priceCode.GetCharge(daysRented);

            }

     

    Inside the Price Class:

     

        public abstract class Price

        {

            public abstract int PriceCode{get;}

     

            public double GetCharge(int daysRented)

            {

                double result = 0;

                switch (PriceCode)

                {

                    case Movie.REGULAR:

                        result += 2;

                        if (daysRented > 2)

                        {

                            result += (daysRented - 2) * 1.5;

                        }

                        break;

                    case Movie.NEW_RELEASE:

                        result += daysRented * 3;

                        break;

                    case Movie.CHILDRENS:

                        result += 1.5;

                        if (daysRented > 3)

                        {

                            result += (daysRented - 3) * 1.5;

                        }

                        break;

                }

                return result;

            }

        }

    (WHEW! and there's more)

    So, the first thing we do is change the method to virtual:

            public virtual double GetCharge(int daysRented)

            {

                double result = 0;

                switch (PriceCode)

                {

                    case Movie.REGULAR:

                        result += 2;

                        if (daysRented > 2)

                        {

                            result += (daysRented - 2) * 1.5;

                        }

                        break;

                    case Movie.NEW_RELEASE:

                        result += daysRented * 3;

                        break;

                    case Movie.CHILDRENS:

                        result += 1.5;

                        if (daysRented > 3)

                        {

                            result += (daysRented - 3) * 1.5;

                        }

                        break;

                }

                return result;

            }

     

    After that we each leg of the case statement as an overriding method inside the sub classes.

        public class RegularPrice : Price

        {

            public override int PriceCode

            {

                get { return Movie.REGULAR; }

            }

            public override double GetCharge(int daysRented)

            {

                double result = 2;

                if (daysRented > 2)

                {

                    result += (daysRented - 2) * 1.5;

                }

                return result;

            }

        }

        public class NewReleasePrice : Price

        {

            public override int PriceCode

            {

                get { return Movie.NEW_RELEASE; }

            }

            public override double GetCharge(int daysRented)

            {

                return daysRented * 3;

            }

        }

        public class ChildrensPrice : Price

        {

            public override int PriceCode

            {

                get

                {

                    return Movie.CHILDRENS;

                }

            }

     

            public override double GetCharge(int daysRented)

            {

                double result = 1.5;

                if (daysRented > 3)

                {

                    result += (daysRented - 3) * 1.5;

                }

                return result;

            }

        }

     

    Once all that is done, we can change the Price.GetCharge method to abstract since there’s nothing left.

       public abstract class Price

        {

            public abstract int PriceCode{get;}

     

            public abstract double GetCharge(int daysRented);

        }

     

    Now we do the same thing with FrequentRenterPoints:

     

            public int getFrequentRenterPoints(int _daysRented)

            {

                if ((PriceCode == Movie.NEW_RELEASE) && _daysRented > 1)

                {

                    return 2;

                }

                else

                {

                    return 1;

                }

            }

     

        public abstract class Price

        {

            public abstract int PriceCode{get;}

     

            public abstract double GetCharge(int daysRented);

     

            public virtual int getFrequentRenterPoints(int _daysRented)

            {

                if ((PriceCode == Movie.NEW_RELEASE) && _daysRented > 1)

                {

                    return 2;

                }

                else

                {

                    return 1;

                }

            }

        }

     

    And Movie is like this:

            public int getFrequentRenterPoints(int _daysRented)

            {

                return _priceCode.getFrequentRenterPoints(_daysRented);

            }

     

    Then we actually don’t move it to abstract, but change the virtual method to return 1 and then modify the NewReleasePrice as such:

     

        public abstract class Price

        {

            public abstract int PriceCode{get;}

     

            public abstract double GetCharge(int daysRented);

     

            public virtual int getFrequentRenterPoints(int daysRented)

            {

                return 1;

            }

        }

     

        public class NewReleasePrice : Price

        {

            public override int PriceCode

            {

                get { return Movie.NEW_RELEASE; }

            }

            public override double GetCharge(int daysRented)

            {

                return daysRented * 3;

            }

            public override int getFrequentRenterPoints(int daysRented)

            {

                //if > 1 then 2, otherwise return 1

                return (daysRented > 1) ? 2 : 1;

            }

        }

     

     

     Here's the code thusfar: (sorry i didn't do a 'before')

    (CLICK)

     

     

    Full story

    Comments (0)

  • Object Oriented Normalization

    When dealing with object oriented design and refactoring, it's important to consider the reasons WHY we want to make the object structures we use. The big thing is Behavior normalization and the second is data normalization and the third is something i would call interaction normalization (the interaction between the behavior of methods and the data their using). 

    I was having a hard time coming up with a concise explanation why I write objects the way that I do because i've mostly just learned it by looking at other people's code in books and examples. However, i found this amazing article/essay about the topic here and it explains in 'just enough' detail what it was that i was ineffective at verbalizing.

    http://www.agiledata.org/essays/classNormalization.html

     

     

    Full story

    Comments (0)

  • Refactoring Part 6: Moving Temps to Properties

    Refactoring continues! Tonight I’m working on the next stage, which is some more removing of temp variables and replacing them with queries. Again, in the book Fowler says, refactor temps out of your methods… later we’ll work on performance issues! (I’m still waiting to see where he does this but he is the master and I am the apprentice.)

     

    Basically, we have the Statement() Method inside Customer that looks like this:

     

            public string Statement()

            {

                double totalAmount = 0;

                int frequentRenterPoints = 0;

                string result = "Rental Record for " + Name + Environment.NewLine;

                foreach (Rental rental in _rentals)

                {

                    //add frequent renter points

                    frequentRenterPoints += rental.FrequentRenterPoints;

     

                    //show figures for this rental

                    result += "\t" + rental.Movie.Title + "\t$" +

                        rental.Charge.ToString() + Environment.NewLine;

                    totalAmount += rental.Charge;

     

                }

                //add footer lines

                result += "Amount owed is $" + totalAmount.ToString() + Environment.NewLine;

                result += "You earned " + frequentRenterPoints.ToString() + " frequent renter points";

                return result;

            }

     

    We’re going to replace the totalAmount and frequentRenterPoints temp variables and move them to Queries of their own. In our case with .net we’re creating our Query methods as properties where possible.

     

    The result is this:

            public string Statement()

            {

               

                string result = "Rental Record for " + Name + Environment.NewLine;

                foreach (Rental rental in _rentals)

                {

                    //show figures for this rental

                    result += "\t" + rental.Movie.Title + "\t$" +

                        rental.Charge.ToString() + Environment.NewLine;

                }

                //add footer lines

                result += "Amount owed is $" + this.TotalCharge.ToString() + Environment.NewLine;

                result += "You earned " + this.FrequentRenterPoints.ToString() + " frequent renter points";

                return result;

            }

            private int FrequentRenterPoints

            {

                get

                {

                    int result = 0;

                    foreach (Rental rental in this._rentals)

                    {

                        result += rental.FrequentRenterPoints;

                    }

                    return result;

                }

            }

            private double TotalCharge

            {

                get

                {

                    double result = 0.0;

                    foreach (Rental rental in this._rentals)

                    {

                        result += rental.Charge;

                    }

                    return result;

                }

            }

     

    Full story

    Comments (0)

  • More backlog

    The idea of the product backlog is that it's prioritized and estimated to be healthy. However, something possibly over looked is that the top (a sprint or more's worth of work) needs to be understood by the product owner well enough that they can make important decisions about it!

    Take a look at this diagram:

    backlogcolored.jpg

    If this was your backlog:

    • Green: Backlog items that the business can answer questions on concisely. Maybe 1 day turnaround on answering a specific question like "what text should be here" or "what will the user experience when they click this button"
    • Yellow: Backlog items that the business has a lot of information about but probably isn't ready to have in a sprint yet. They're probably still gathering requirements from stakeholders and users.
    • Orange: These are items that are probably really fuzzy to anyone. They're more of a wish list of things and aren't really fleshed out more than a high level 10,000 foot view or description.
    • Red: Most likely these are something that someone asked for, but very likely brings no real business value and have been pushed farther and farther down.

    The significance of the dark bar was just me accidentally drawing a thicker line, however... it is also probably a good place say "anything below here isn't fleshed out enough to become part of a sprint yet". This has to be your product owner's responsibility.

     

     

    Full story

    Comments (0)

  • Change happens!

    Sorry for the double blog, but i really have to just get this off my chest so to speak. I was thinking about forrest gump who said "It happens" when i wrote the title to this, but basically I've enountered this quite a bit lately:

    "We're changing too much, when things settle down, then we'll do something"

    I'm sorry, but... what? This is agile, change happens, that's the whole 'cool' thing about it. We can handle change!

    Can't we?

    Not when the rug is pulled out from under us we can't.

    When you say that you're going to do Scrum, you're saying this to the team.

    "Hey, we're giving you this prioritized list of work, you choose how much you can do in 30 days, you go and do it, call us if you need anything, but when you come back in 30 days we expect that stuff to be done just as we described it to you today"

    Anyhow the point is, a team needs SOMETHING that is constant:

    give them a constant iteration length

    give them a sprint planning, scrum meeting, and retrospective that they can count on.

    give them a product owner that can answer their questions within 1 day (or less)

    give them uninterrupted time (iteration length) to work.

    hold them accountable at the end of the sprints. (as a team, not as individuals)

    When something increases in time, the team needs to know that they have to remove something else from the backlog, or put that item on the backlog.

    In fact, here's something hypothetical i'd like to show you.

    lolburndown.jpg

    if this is a burndown, what do you suppose probably happened here...

    still thinking? <pause here until you got an idea>

    Here's what probably happened: The team didn't take enough work, and they decided to start doing more and more of a certain backlog item with the customer. Basically scope was sneaking in on them because they felt like they had time to spare. This is where the scrum master should have probably stepped in and said "hey what's going on here?"

     

     

    Full story

    Comments (0)

  • Retrospectives: Not a whine session.

    Crystal Clear methodology says teams get better through "Reflective Improvement". Waterfall shops i've had experience with prescribe a "Post Mortem" or a "Lessons Learned" as if to weep about the past or to punish those who need "Taught a lesson". When i worked at a helpdesk we had a monthly team meeting and a bi monthly training session. When i worked at a restaurant, we gathered at the bar after hours and talked about what we could work on together to make more tips, sales ideas, etc.

    The common ground that i find with the successful teams i've been in is that they all revolve around the act of recognizing places where they could improve and working slowly towards those improvements wherever they could.

    First off... Retrospectives are NOT:

    1. a place to vent
    2. a pulpit to shout your pet peaves the loudest to get your agenda
    3. a soapbox to preach best practices or argue some other holy war
    4. a replacement for summarizing the sprint/iteration and recognizing commitments

    A retrospective is:

    1. a chance to look at some real data about the team
    2. a chance to hear how you may have impacted a team member (favorably or unfavorably)
    3. a chance for you to decide where you want to see the team make improvements
    4. a chance for every voice to be heard in a constructive way

    Now i'm going to pimp a book i've been reading lately called "Agile Retrospectives - making good teams great" by derby and larsen. Just like Fowler's book being the definitive refactoring book i think this is clearly the definitive book on retrospectives (mainly because i don't know of any other books for either topic! haha)

    Let me summarize what these two ladies suggest you do for a retrospective to keep in on point, concise, interactive, and productive.

    1. Set up the stage: they give you tons of "set the stage" activities to use with your team. Step by step guidance on how to go through them. Plus this generated a few ideas of my own just by reading these. The big point here is that you give everyone on the team a chance to talk briefly, with 1 or 2 words so that it's easy to get involved with the discussion.
    2. Gather Data: a retrospective doesn't work without having some type of information to work on. Sometimes, you have to just wing it. Like right now, my gathering data is basically (what did we do good? what did we suck at?)
    3. Generate Insights: this stage is all about letting the team think of reasons why they were awesome or reasons why they sucked. This isn't the time for discussion on  what to do about it yet, but a chance to go over the real details of what they saw, heard, felt, and experienced during these moments of bliss or frustration. This will help them do the next stage.
    4. Deciding what to do: now that we have insights into why these things happened (hopefully). We have to figure out what it is that we're going to do. In my case right now, i'm limiting the team to 1 thing that they're all going to vote on to 'work on' and then generate a list of ideas through brainstorming that they'll propose will 'help' this area of need. For example: We want code to be testable sooner... well you could write unit tests first via TDD. You could write the UI first for UAT scripting. You could have a tester pair up with you to work on something and build it from their perspective first. maybe more.
    5. close the retrospective: this is i thought would be self explanatory, but it's not really. Take the extra effort to thank the team for their efforts, and for being involved with the retrospective.

     

     

     

     

    Full story

    Comments (0)

  • Product backlogs

    I'm sortof breaking the flow of refactoring to make a quick attempt to talk about product backlogs.

     

    Let’s say for a moment, you’re a parent and your young children would like a treehouse.

     

    You ask them to show you the tree they want it in, they show you the tree.

    “We want it in the northwest tree”

     

    You ask them how high they want it off the ground.

    “we want the floor to start 8 feet off the ground”

     

    You ask if they want a way to get into it.

    “We want a rope ladder that drops down from a hatch”

     

    You help them clarify:

    “We want a rope ladder”

    “We want a trap door”

    “We want the rope ladder to be deployed from the trap door”

     

    They agree.

     

    They say,

    “We want windows”

    “We want furniture”

    “We want red paint”

    “we want a roof on it”

    “we want a tire swing to hang from it”

     

    and maybe your kids can't explain what they want very well and you have to help them.

    and maybe your kids get frustrated when you ask them to choose which is more important, the trap door or the rope ladder.

    and maybe your kids refuse to talk to you about it and you have to decide some things for them.

     

    anyhow, think about your backlog... are you doing all that you can to make sure it's just enough detail to get started and ensuring it stays healthy (estimated and prioritized)?

    Full story

    Comments (0)

  • Refactoring Part 5: Extracting more Properties

    If you’re just starting to follow this blog series, the code to start off today is Here

     

    With the same reasoning behind why we extracted Charge let’s work on extracting FrequentRenterPoints into a property as well.

     

    First examine the bold/italic section of this code:

            public string Statement()

            {

                double totalAmount = 0;

                int frequentRenterPoints = 0;

                string result = "Rental Record for " + Name + Environment.NewLine;

                foreach (Rental rental in _rentals)

                {

                    //add frequent renter points

                    frequentRenterPoints++;

                    //add bonus for two day release rental

                    if ((rental.Movie.PriceCode == Movie.NEW_RELEASE) &&

                        rental.DaysRented > 1) frequentRenterPoints++;

     

                    //show figures for this rental

                    result += "\t" + rental.Movie.Title + "\t$" +

                        rental.Charge.ToString() + Environment.NewLine;

                    totalAmount += rental.Charge;

     

                }

                //add footer lines

                result += "Amount owed is $" + totalAmount.ToString() + Environment.NewLine;

                result += "You earned " + frequentRenterPoints.ToString() +

    " frequent renter points";

                return result;

       }

     

    Basically,  we’re going to extract that out into the rental object. So the code for Customer statement will look like this:

            public string Statement()

            {

                double totalAmount = 0;

                int frequentRenterPoints = 0;

                string result = "Rental Record for " + Name + Environment.NewLine;

                foreach (Rental rental in _rentals)

                {

                    //add frequent renter points

                    frequentRenterPoints += rental.FrequentRenterPoints;

     

                    //show figures for this rental

                    result += "\t" + rental.Movie.Title + "\t$" +

                        rental.Charge.ToString() + Environment.NewLine;

                    totalAmount += rental.Charge;

     

                }

                //add footer lines

                result += "Amount owed is $" + totalAmount.ToString() + Environment.NewLine;

                result += "You earned " + frequentRenterPoints.ToString() + " frequent renter points";

                return result;

          }

     

    And we’ll add the new property to Rental that looks like this:

            public int FrequentRenterPoints

            {

                get

                {

                    if( (Movie.PriceCode == Movie.NEW_RELEASE) && DaysRented > 1)

                    {

                        return 2;

                    }

                    else

                    {

                        return 1;

                    }

                }

            }      

     

    in the "IF" statement I’m pretty explicit with the brackets because I think it communicates better the intention of the code…

    Also at this point you may be thinking, wow these articles are short and you could have just done all these steps in one example and it would have made sense.... I think fowler does this to purposefully show each individual step as an increment, where we verify with testing, reviewing our changes to ensure nothing is broken. So i'll do the same, one small change per article.

    Full story

    Comments (0)

  • Refactoring Part 4: Replacing temp variable with Query

    Last time we moved a method, what I didn’t do was go through and find all the references and fix them to point to the new method. So we’ll do that now.

     

    Basically it’s just one spot in this code, but in your apps you may have to ‘find all references’ which is actually a right click functionality in VS2008 (and vs2005, but vs.net seems to be flakey on it)

    From:

        foreach (Rental rental in _rentals)

                {

                    //determine amount for each line

                    double thisAmount = AmountFor(rental);

    To:

     

                foreach (Rental rental in _rentals)

                {

                    //determine amount for each line

                    double thisAmount = rental.Charge;

     

    Then we can remove the old method

    AmountFor(Rental rental)

     

    Compile and verify everything works fine.

     

    Optionally you could leave the method in if you’re worried about other apps using the public interface to this method.

     

     

    Anyhow, now time for

     

    Part 4: Replacing temp variable with Query

     

    If you look at the statement method, you’ll see that thisAmount is redundant. Everywhere we see thisAmount we’re going to replace with the property from rental. If you’re worried about performance, Fowler urges us to refactor and that he’ll cover optimizing later on. Better to refactor first then optimize later he says. I haven’t finished the book but I’ll trust that’s the best thing to do at this point and move forward.

     

    The new statement method will look like this:

     

    public string Statement()

            {

                double totalAmount = 0;

                int frequentRenterPoints = 0;

                string result = "Rental Record for " + Name + Environment.NewLine;

                foreach (Rental rental in _rentals)

                {

                    //add frequent renter points

                    frequentRenterPoints++;

                    //add bonus for two day release rental

                    if ((rental.Movie.PriceCode == Movie.NEW_RELEASE) &&

                        rental.DaysRented > 1) frequentRenterPoints++;

     

                    //show figures for this rental

                    result += "\t" + rental.Movie.Title + "\t$" +

                        rental.Charge.ToString() + Environment.NewLine;

                    totalAmount += rental.Charge;

     

                }

                //add footer lines

                result += "Amount owed is $" + totalAmount.ToString() + Environment.NewLine;

                result += "You earned " + frequentRenterPoints.ToString() + " frequent renter points";

                return result;

            }

     

    .net Terminology note: I think that java developers call these getter methods "queries"... However, in .net we use properties. Not always is there a 1 to 1 translation but in general when you see the word Query used in fowler's book try to use a property to be more ".Net" friendly.

     

    Also: if a getBlah() method requires parameters... you can't really make it a property in C#... you can in VB.Net though.

    Full story

    Comments (0)

  • Refactoring part 3: Move Method

     

    In the previous example, the amountFor(Rental rental) {} method was inside the customer. Since the method doesn’t use any data from customer and only uses data from a rental Fowler alerts us that we should move this method to where it has the least viscosity for change.. and that is over in the Rental Object.

     

    So to be backwards compat inside of Customer you have this:

     

            private static double AmountFor(Rental rental)

            {

                return rental.Charge;

            }

     

    And then in Rental you’d have this new property:

            public double Charge

            {

                get

                {

     

                    double result = 0;

                    switch (Movie.PriceCode)

                    {

                        case Movie.REGULAR:

                            result += 2;

                            if (DaysRented > 2)

                            {

                                result += (DaysRented - 2) * 1.5;

                            }

                            break;

                        case Movie.NEW_RELEASE:

                            result += DaysRented * 3;

                            break;

                        case Movie.CHILDRENS:

                            result += 1.5;

                            if (DaysRented > 3)

                            {

                                result += (DaysRented - 3) * 1.5;

                            }

                            break;

                    }

                    return result;

                }

            }

     

     

    IN the book, they're using Java and java doesn't have properties that i'm aware of. they use setters and getters. So i've extrapolated that anywhere fowler uses set or get i'm going to try to convert it to a property where easily applicable.

     

    This particular property may be sort of big, but that will change soon :)

    Full story

    Comments (0)

  1. 1
  2. 2
  3. Next page