Refactoring<br />Chapter 9<br />Simplifying Conditional Expressions<br />
Read this<br />and then read this<br />Decompose Conditional<br />if (date.before (SUMMER_START) || date.after(SUMMER_END)...
Consolidate Conditional Expression<br />Before:<br />After:<br />double disabilityAmount() {<br />       if (_seniority < ...
Before<br />if (isSpecialDeal()) {<br />doSomePreparation();<br />doNonRelatedWork();<br />	total = price * 0.95;<br />	se...
Consolidate Duplicate Conditional Fragments<br />After<br />doNonRelatedWork();<br />doSomePreparation();<br />if (isSpeci...
Remove Control Flag<br />Trace this<br />void checkSecurity(String[] people) {<br />boolean found = false;<br />	for (int ...
Remove Control Flag<br />○use return, break, continue …<br />✕set a flag and check somewhere later<br />
Alternative 1:<br />Remove Control Flag<br />void checkSecurity(String[] people) {<br />	for (int i = 0; i < people.length...
Alternative 2:<br />Remove Control Flag<br />void checkSecurity(String[] people) {<br />	String found = foundMiscreant(peo...
Before<br />Replace Nested Conditional with Guard Clauses<br />double getPayAmount() {<br />	double result;<br />	if (_isD...
After<br />Replace Nested Conditional with Guard Clauses<br />double getPayAmount() {<br />	if (_isDead)<br />		return dea...
Mind implicit semantics<br /><ul><li>Guard clause</li></ul>-> (somehow) exceptional condition<br /><ul><li>if else</li></u...
Replace Nested Conditional with Guard Clauses<br />However, you might have seen this …<br />if (aquireResource1()) {<br />...
Replace Nested Conditional with Guard Clauses<br />or this …<br />if (false == aquireResource1())<br />return;<br />if (fa...
Before<br />Replace Conditional with Polymorphism<br />class Employee...<br />    int payAmount(Employee) {<br />        s...
!<br />○Polymorphism might be better, usually<br />Replace Conditional with Polymorphism<br />switch case<br />clauses<br />
class Employee...<br />intpayAmount() {<br />        return _type.payAmount(this);<br />}<br />class Salesman...<br />intp...
<ul><li>Same with Replace Conditional with Polymorphism
deal with special cases extensively checked
check type -> check NULL
Before:</li></ul>Introduce Null Object<br />class Customer...<br />    public String getName() {...}<br />    public Billi...
After<br />Introduce Null Object<br />plan = customer.getPlan();<br />class NullCustomer...<br />    public BillingPlanget...
Upcoming SlideShare
Loading in...5
×

重構—改善既有程式的設計(chapter 9)

866

Published on

Published in: Education, Technology, Business
0 Comments
0 Likes
Statistics
Notes
  • Be the first to comment

  • Be the first to like this

No Downloads
Views
Total Views
866
On Slideshare
0
From Embeds
0
Number of Embeds
0
Actions
Shares
0
Downloads
55
Comments
0
Likes
0
Embeds 0
No embeds

No notes for slide

重構—改善既有程式的設計(chapter 9)

  1. 1. Refactoring<br />Chapter 9<br />Simplifying Conditional Expressions<br />
  2. 2. Read this<br />and then read this<br />Decompose Conditional<br />if (date.before (SUMMER_START) || date.after(SUMMER_END))<br /> charge = quantity * _winterRate + _winterServiceCharge;<br />else charge = quantity * _summerRate;<br />if (notSummer(date))<br /> charge = winterCharge(quantity);<br />else<br /> charge = summerCharge (quantity);<br />
  3. 3. Consolidate Conditional Expression<br />Before:<br />After:<br />double disabilityAmount() {<br /> if (_seniority < 2) return 0;<br /> if (_monthsDisabled > 12) return 0;<br /> if (_isPartTime) return 0;<br /> // ...<br />}<br />double disabilityAmount() {<br /> if (isNotEligableForDisability()) return 0;<br /> // ...<br />}<br />
  4. 4. Before<br />if (isSpecialDeal()) {<br />doSomePreparation();<br />doNonRelatedWork();<br /> total = price * 0.95;<br /> send();<br />doSomeCleanUp();<br />}<br />else {<br />doSomePreparation();<br /> total = price * 0.98;<br /> send();<br />doNonRelatedWork();<br />doSomeCleanUp();<br />}<br />Consolidate Duplicate Conditional Fragments<br />
  5. 5. Consolidate Duplicate Conditional Fragments<br />After<br />doNonRelatedWork();<br />doSomePreparation();<br />if (isSpecialDeal())<br /> total = price * 0.95;<br />else<br /> total = price * 0.98;<br />send();<br />doSomeCleanUp();<br />
  6. 6. Remove Control Flag<br />Trace this<br />void checkSecurity(String[] people) {<br />boolean found = false;<br /> for (int i = 0; i < people.length; i++) {<br /> if (! found) {<br /> if (people[i].equals ("Don")){<br />sendAlert();<br /> found = true;<br /> }<br /> if (people[i].equals ("John")){<br />sendAlert();<br /> found = true;<br /> }<br /> }<br /> }<br />}<br />
  7. 7. Remove Control Flag<br />○use return, break, continue …<br />✕set a flag and check somewhere later<br />
  8. 8. Alternative 1:<br />Remove Control Flag<br />void checkSecurity(String[] people) {<br /> for (int i = 0; i < people.length; i++) {<br /> if (people[i].equals ("Don")){<br />sendAlert();<br /> break;<br /> }<br /> if (people[i].equals ("John")){<br />sendAlert();<br /> break;<br /> }<br /> }<br />}<br />
  9. 9. Alternative 2:<br />Remove Control Flag<br />void checkSecurity(String[] people) {<br /> String found = foundMiscreant(people);<br />someLaterCode(found);<br />}<br />String foundMiscreant(String[] people) {<br /> for (int i = 0; i < people.length; i++) {<br /> if (people[i].equals ("Don")){<br />sendAlert();<br /> return "Don";<br /> }<br /> if (people[i].equals ("John")){<br />sendAlert();<br /> return "John";<br /> }<br /> }<br /> return "";<br />}<br />
  10. 10. Before<br />Replace Nested Conditional with Guard Clauses<br />double getPayAmount() {<br /> double result;<br /> if (_isDead) {<br /> result = deadAmount();<br /> } else {<br /> if (_isSeparated) {<br /> result = separatedAmount();<br /> } else {<br /> if (_isRetired) result = retiredAmount();<br /> else result = normalPayAmount();<br /> }<br /> }<br /> return result;<br />}<br />
  11. 11. After<br />Replace Nested Conditional with Guard Clauses<br />double getPayAmount() {<br /> if (_isDead)<br /> return deadAmount();<br /> if (_isSeparated)<br /> return separatedAmount();<br /> if (_isRetired)<br /> return retiredAmount();<br /> return normalPayAmount();<br />};<br />
  12. 12. Mind implicit semantics<br /><ul><li>Guard clause</li></ul>-> (somehow) exceptional condition<br /><ul><li>if else</li></ul>-> two equivalent normal conditions<br />Replace Nested Conditional with Guard Clauses<br />
  13. 13. Replace Nested Conditional with Guard Clauses<br />However, you might have seen this …<br />if (aquireResource1()) {<br /> if (aquireResource2()) {<br />if (aquireResource3()){<br /> if (aquireResource4()) {<br /> doRealWork();<br />releaseResource4();<br /> }<br /> releaseResource3();<br /> }<br /> releaseResource2();<br /> }<br />releaseResource1();<br />}<br />
  14. 14. Replace Nested Conditional with Guard Clauses<br />or this …<br />if (false == aquireResource1())<br />return;<br />if (false == aquireResource2()) {<br />releaseResource1();<br /> return;<br />}<br />if (false == aquireResource3()){<br />releaseResource2();<br />releaseResource1();<br />return;<br />}<br />doRealWork();<br />releaseResource3();<br />releaseResource2();<br />releaseResource1();<br />return;<br />
  15. 15. Before<br />Replace Conditional with Polymorphism<br />class Employee...<br /> int payAmount(Employee) {<br /> switch (getType()) {<br /> case EmployeeType.ENGINEER:<br /> return _monthlySalary;<br /> case EmployeeType.SALESMAN:<br /> return _monthlySalary + _commission;<br /> case EmployeeType.MANAGER:<br /> return _monthlySalary + _bonus;<br /> default:<br /> throw new RuntimeException("Incorrect Employee");<br /> }<br /> }<br />
  16. 16. !<br />○Polymorphism might be better, usually<br />Replace Conditional with Polymorphism<br />switch case<br />clauses<br />
  17. 17. class Employee...<br />intpayAmount() {<br /> return _type.payAmount(this);<br />}<br />class Salesman...<br />intpayAmount(Employee emp) {<br /> return emp.getMonthlySalary() + emp.getCommission();<br /> }<br />class Manager...<br />intpayAmount(Employee emp) {<br /> return emp.getMonthlySalary() + emp.getBonus();<br /> }<br />After<br />Replace Conditional with Polymorphism<br />
  18. 18. <ul><li>Same with Replace Conditional with Polymorphism
  19. 19. deal with special cases extensively checked
  20. 20. check type -> check NULL
  21. 21. Before:</li></ul>Introduce Null Object<br />class Customer...<br /> public String getName() {...}<br /> public BillingPlangetPlan() {...}<br /> public PaymentHistorygetHistory() {...}<br />if (customer == null) plan = BillingPlan.basic();<br />else plan = customer.getPlan();<br />
  22. 22. After<br />Introduce Null Object<br />plan = customer.getPlan();<br />class NullCustomer...<br /> public BillingPlangetPlan(){<br /> return BillingPlan.basic();<br /> }<br />
  23. 23. Write your assumption explicitly and clearly<br />Introduce Assertion<br /> double getExpenseLimit() {<br />// should have either expense limit or a primary project<br /> return (_expenseLimit != NULL_EXPENSE) ?<br /> _expenseLimit:<br /> _primaryProject.getMemberExpenseLimit();<br />}<br /> double getExpenseLimit() {<br />Assert.isTrue (_expenseLimit != NULL_EXPENSE || _primaryProject != null);<br /> return (_expenseLimit != NULL_EXPENSE) ?<br /> _expenseLimit:<br /> _primaryProject.getMemberExpenseLimit();<br />}<br />
  24. 24. Do NOT overuse<br />If code does work without the assertion, remove it.<br />Introduce Assertion<br />
  25. 25. Notes<br />Save brain power<br />Break/prune eye-tracing as early as possible<br />Don’t Repeat Yourself<br />
  1. A particular slide catching your eye?

    Clipping is a handy way to collect important slides you want to go back to later.

×