├── 01 Encapsullate Collection ├── problem │ └── Order.js ├── solution │ └── Order.js └── solutions_using_prototype │ ├── solution1 │ └── Order.js │ └── solution2 │ └── Order.js ├── 02 Move Method ├── problem │ ├── AccountInterest.js │ └── BankAccount.js ├── solution.js └── solution │ ├── AccountInterest.js │ └── BankAccount.js ├── 03 Pull Up Method ├── problem │ ├── Car.js │ ├── Direction.js │ ├── Motorcycle.js │ └── Vehicle.js └── solution │ ├── Car.js │ ├── Direction.js │ ├── Motorcycle.js │ └── Vehicle.js ├── 04 Push Down Method ├── problem │ ├── Animal.js │ ├── Cat.js │ └── Dog.js └── solution │ ├── Animal.js │ ├── Cat.js │ └── Dog.js ├── 05 Pull Up Field ├── problem │ ├── Account.js │ ├── CheckingAccount.js │ └── SavingsAccount.js └── solution │ ├── Account.js │ ├── CheckingAccount.js │ └── SavingsAccount.js ├── 06 Push Down Field ├── problem │ ├── BugTask.js │ ├── FeatureTask.js │ └── Task.js └── solution │ ├── BugTask.js │ ├── FeatureTask.js │ └── Task.js ├── 07 Rename (method, class, parameter) ├── problem │ └── Person.js └── solution │ └── Employee.js ├── 08 Replace Inheritance with Delegation ├── problem │ ├── Child.js │ └── Sanitation.js └── solution │ ├── Child.js │ └── Sanitation.js ├── 09 Extract Interface ├── problem │ ├── ClassRegistration.js │ └── RegistrationProcessor.js └── solution │ ├── ClassRegistration.js │ ├── InterfaceRegistration.js │ └── RegistrationProcessor.js ├── 10 Extract Method ├── problem │ └── Receipt.js └── solution │ └── Receipt.js ├── 11 Switch to Strategy ├── problem │ └── switch.js └── solution │ ├── switch.js │ └── switch2.js ├── 12 Break Dependencies ├── problem │ ├── AnimalFeedingService.js │ └── Feeder.js └── solution │ ├── AnimalFeedingService.js │ ├── Feeder.js │ ├── FeederService.js │ └── InterfaceFeederService.js ├── 13 Extract Method Object ├── problem │ ├── Order.js │ └── OrderLineItem.js └── solution │ ├── Order.js │ ├── OrderCalculator.js │ └── OrderLineItem.js ├── 14 Break Responsibilities ├── problem │ ├── Customer.js │ └── Video.js └── solution │ ├── Customer.js │ └── Video.js ├── 15 Remove Duplication ├── problem │ └── MedicalRecord.js └── solution │ └── MedicalRecord.js ├── 16 Encapsulate Conditional ├── problem │ └── RemoteControl.js └── solution │ └── RemoteControl.js ├── 17 Extract Superclass ├── problem │ └── Dog.js └── solution │ ├── Animal.js │ └── Dog.js ├── 18 Replace exception with conditional ├── problem │ ├── Microwave.js │ └── MicrowaveMotor.js └── solution │ ├── Microwave.js │ └── MicrowaveMotor.js ├── 19 Extract Factory Class ├── problem │ └── PoliceCarController.js └── solution │ ├── InterfacePoliceCarFactory.js │ ├── PoliceCarController.js │ └── PoliceCarFactory.js ├── 20 Extract SubClass ├── problem │ └── Registration.js └── solution │ ├── NonRegistration.js │ └── Registration.js ├── 21 Collapse Hierarchy ├── problem │ ├── StudentWebsite.js │ └── Website.js └── solution │ └── Website.js ├── 22 Break Method ├── problem │ ├── CashRegister.js │ ├── Customer.js │ └── Product.js └── solution │ ├── CashRegister.js │ ├── Customer.js │ └── Product.js ├── 23 Introduce Parameter Object ├── problem │ └── Registration.js └── solution │ ├── Registration.js │ └── RegistrationContext.js ├── 24 Remove Arrowhead Antipattern ├── problem │ └── Security.js └── solution │ └── Security.js ├── 25 Introduce Design By Contract checks ├── problem │ └── CashRegister.js └── solution │ └── CashRegister.js ├── 26 Remove Double Negative ├── problem │ ├── Customer.js │ └── Order.js └── solution │ ├── Customer.js │ └── Order.js ├── 27 Remove God Classes ├── problem │ └── CustomerService.js └── solution │ ├── CustomerOrderService.js │ └── CustomerRegistrationService.js ├── 28 Rename boolean method ├── problem │ └── BankAccount.js └── solution │ └── BankAccount.js ├── 29 Remove Middle Man ├── problem │ ├── AccountDataProvider.js │ ├── AccountManager.js │ └── Consumer.js └── solution │ ├── AccountDataProvider.js │ └── Consumer.js ├── 30 Return ASAP ├── problem │ └── Order.js └── solution │ └── Order.js ├── 31 Replace conditional with Polymorphism ├── problem │ ├── Customer.js │ ├── Employee.js │ ├── NonEmployee.js │ └── OrderProcessor.js └── solution │ ├── Customer.js │ ├── Employee.js │ ├── NonEmployee.js │ └── OrderProcessor.js ├── Array_Sum.js └── README.md /01 Encapsullate Collection/problem/Order.js: -------------------------------------------------------------------------------- 1 | function Order() { 2 | this.aOrderLines = []; 3 | this.nOrderTotal = 0; 4 | } 5 | Order.prototype.getOrderLines = function () { 6 | return this.aOrderLines; 7 | }; 8 | Order.prototype.addOrderLine = function (oOrderLine) { 9 | this.nOrderTotal += oOrderLine.nTotal; 10 | this.aOrderLines.push(oOrderLine); 11 | }; 12 | Order.prototype.removeOrderLine = function (oOrderLineItem) { 13 | var nOrderTotal; 14 | oOrderLine = this.aOrderLines.map(function (oOrder) { 15 | return oOrder === oOrderLineItem; 16 | })[0]; 17 | if (typeof oOrderLine === 'undefined' || oOrderLine === null) { 18 | return; 19 | } 20 | this.nOrderTotal -= oOrderLine.nTotal; 21 | this.aOrderLines.splice(this.nOrderTotal, 1); 22 | }; -------------------------------------------------------------------------------- /01 Encapsullate Collection/solution/Order.js: -------------------------------------------------------------------------------- 1 | function Order() { 2 | var aOrderLines = []; 3 | this.nOrderTotal = 0; 4 | 5 | this.getOrderLines = function () { 6 | return aOrderLines.concat(); 7 | }; 8 | this.addOrderLine = function (oOrderLine) { 9 | this.nOrderTotal += oOrderLine.nTotal; 10 | aOrderLines.push(oOrderLine); 11 | }; 12 | this.removeOrderLine = function (oOrderLineItem) { 13 | var oOrderLine; 14 | oOrderLine = aOrderLines.map(function (oOrder) { 15 | return oOrder === oOrderLineItem; 16 | })[0]; 17 | if (typeof oOrderLine === 'undefined' || oOrderLine === null) { 18 | return; 19 | } 20 | this.nOrderTotal -= oOrderLine.nTotal; 21 | aOrderLines.splice(this.nOrderTotal, 1); 22 | }; 23 | } 24 | -------------------------------------------------------------------------------- /01 Encapsullate Collection/solutions_using_prototype/solution1/Order.js: -------------------------------------------------------------------------------- 1 | // This solution takes advantage of prototype Thanks RoryH 2 | function Order() { 3 | this.nId = Unique.getKey(); // Unique.getKey is an static method to get an unique key for instance. 4 | this.nOrderTotal = 0; 5 | } 6 | Order.prototype = (function() 7 | { 8 | var oOrderLines = {}; 9 | var setOrderLinesByInstance = function(oInstance) 10 | { 11 | if(typeof oOrderLines[oInstance.nId] === 'undefined') 12 | { 13 | oOrderLines[oInstance.nId] = []; 14 | } 15 | }; 16 | return { 17 | getOrderLines: function() 18 | { 19 | setOrderLinesByInstance(this); 20 | return oOrderLines[this.nId].concat(); 21 | }, 22 | addOrderLine: function(oOrderLine) 23 | { 24 | setOrderLinesByInstance(this); 25 | this.nOrderTotal += oOrderLine.nTotal; 26 | oOrderLines[this.nId].push(oOrderLine); 27 | }, 28 | removeOrderLine: function(oOrderLineItem) 29 | { 30 | var oOrderLine; 31 | setOrderLinesByInstance(this); 32 | oOrderLine = oOrderLines[this.nId].map(function (oOrder) { 33 | return oOrder === oOrderLineItem; 34 | })[0]; 35 | if (typeof oOrderLine === 'undefined' || oOrderLine === null) { 36 | return; 37 | } 38 | this.nOrderTotal -= oOrderLine.nTotal; 39 | oOrderLines[this.nId].splice(this.nOrderTotal, 1); 40 | } 41 | }; 42 | }()); -------------------------------------------------------------------------------- /01 Encapsullate Collection/solutions_using_prototype/solution2/Order.js: -------------------------------------------------------------------------------- 1 | function Order() 2 | { 3 | var aOrderLines = []; 4 | this.getOrderLines = function() 5 | { 6 | return aOrderLines.concat(); 7 | }; 8 | this.setOrderLines = function(aOrder) 9 | { 10 | var aToConcat = aOrder || []; 11 | aOrderLines = aOrderLines.concat(aToConcat); 12 | aToConcat = null; 13 | }; 14 | } 15 | Order.prototype.addOrderLine = function (oOrderLine) 16 | { 17 | var aOrderLines = []; 18 | this.nOrderTotal += oOrderLine.nTotal; 19 | aOrderLines.push(oOrderLine); 20 | this.setOrderLines(aOrderLines); 21 | aOrderLines = null; 22 | }; 23 | Order.prototype.removeOrderLine = function(oOrderLineItem) 24 | { 25 | var aOrderLines = this.getOrderLines(), 26 | oOrderLine; 27 | oOrderLine = aOrderLines.map(function (oOrder) { 28 | return oOrder === oOrderLineItem; 29 | })[0]; 30 | if (typeof oOrderLine === 'undefined' || oOrderLine === null) { 31 | return; 32 | } 33 | this.nOrderTotal -= oOrderLine.nTotal; 34 | aOrderLines.splice(this.nOrderTotal, 1); 35 | this.setOrderLines(aOrderLines); 36 | oOrderLine = aOrderLines = null; 37 | }; -------------------------------------------------------------------------------- /02 Move Method/problem/AccountInterest.js: -------------------------------------------------------------------------------- 1 | function AccountInterest(oAccount) { 2 | this.oAccount = oAccount; 3 | } 4 | AccountInterest.prototype.getInterestRate = function () { 5 | return this.oAccount.calculateInterestRate(); 6 | }; 7 | AccountInterest.prototype.isIntroductoryRate = function () { 8 | return this.oAccount.calculateInterestRate() < 0.05; 9 | }; -------------------------------------------------------------------------------- /02 Move Method/problem/BankAccount.js: -------------------------------------------------------------------------------- 1 | function BankAccount(nAccountAge, nCreditScore, oAccountInterest) { 2 | this.nAccountAge = nAccountAge; 3 | this.nCreditScore = nCreditScore; 4 | this.oAccountInterest = oAccountInterest; 5 | } 6 | BankAccount.prototype.calculateInterestRate = function () { 7 | if (this.nCreditScore > 900) { 8 | return 0.02; 9 | } 10 | if (this.nAccountAge > 10) { 11 | return 0.03; 12 | } 13 | return 0.05; 14 | }; -------------------------------------------------------------------------------- /02 Move Method/solution.js: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tcorral/Refactoring_Patterns/6b281e5c8e529e1b3b2e46b61a7324c161a8e8bd/02 Move Method/solution.js -------------------------------------------------------------------------------- /02 Move Method/solution/AccountInterest.js: -------------------------------------------------------------------------------- 1 | function AccountInterest(oAccount) { 2 | this.oAccount = oAccount; 3 | } 4 | AccountInterest.prototype.getInterestRate = function () { 5 | return this.calculateInterestRate(); 6 | }; 7 | AccountInterest.prototype.isIntroductoryRate = function () { 8 | return this.calculateInterestRate() < 0.05; 9 | }; 10 | AccountInterest.prototype.calculateInterestRate = function () { 11 | if (this.oAccount.nCreditScore > 900) { 12 | return 0.02; 13 | } 14 | if (this.oAccount.nAccountAge > 10) { 15 | return 0.03; 16 | } 17 | return 0.05; 18 | }; -------------------------------------------------------------------------------- /02 Move Method/solution/BankAccount.js: -------------------------------------------------------------------------------- 1 | function BankAccount(nAccountAge, nCreditScore) { 2 | this.nAccountAge = nAccountAge; 3 | this.nCreditScore = nCreditScore; 4 | } -------------------------------------------------------------------------------- /03 Pull Up Method/problem/Car.js: -------------------------------------------------------------------------------- 1 | function Car() { 2 | Vehicle.call(this); 3 | } 4 | Car.prototype = new Vehicle(); 5 | Car.prototype.turn = function (oDirection) { 6 | // code here. 7 | }; -------------------------------------------------------------------------------- /03 Pull Up Method/problem/Direction.js: -------------------------------------------------------------------------------- 1 | function Direction() { 2 | this.nLeft = 0; 3 | this.nRight = 1; 4 | } -------------------------------------------------------------------------------- /03 Pull Up Method/problem/Motorcycle.js: -------------------------------------------------------------------------------- 1 | function Motorcycle() { 2 | Vehicle.call(this); 3 | } 4 | Motorcycle.prototype = new Vehicle(); -------------------------------------------------------------------------------- /03 Pull Up Method/problem/Vehicle.js: -------------------------------------------------------------------------------- 1 | function Vehicle() { 2 | // Other methods 3 | } -------------------------------------------------------------------------------- /03 Pull Up Method/solution/Car.js: -------------------------------------------------------------------------------- 1 | function Car() { 2 | Vehicle.call(this); 3 | } 4 | Car.prototype = new Vehicle(); -------------------------------------------------------------------------------- /03 Pull Up Method/solution/Direction.js: -------------------------------------------------------------------------------- 1 | function Direction() { 2 | this.nLeft = 0; 3 | this.nRight = 1; 4 | } -------------------------------------------------------------------------------- /03 Pull Up Method/solution/Motorcycle.js: -------------------------------------------------------------------------------- 1 | function Motorcycle() { 2 | Vehicle.call(this); 3 | } 4 | Motorcycle.prototype = new Vehicle(); -------------------------------------------------------------------------------- /03 Pull Up Method/solution/Vehicle.js: -------------------------------------------------------------------------------- 1 | function Vehicle() { 2 | 3 | } 4 | Vehicle.prototype.turn = function (oDirection) { 5 | // code here 6 | }; -------------------------------------------------------------------------------- /04 Push Down Method/problem/Animal.js: -------------------------------------------------------------------------------- 1 | function Animal() { 2 | 3 | } 4 | Animal.prototype.bark = function () { 5 | // code to bark 6 | }; -------------------------------------------------------------------------------- /04 Push Down Method/problem/Cat.js: -------------------------------------------------------------------------------- 1 | function Cat() { 2 | Animal.call(this); 3 | } 4 | Cat.prototype = new Animal(); -------------------------------------------------------------------------------- /04 Push Down Method/problem/Dog.js: -------------------------------------------------------------------------------- 1 | function Dog() { 2 | Animal.call(this); 3 | } 4 | Dog.prototype = new Animal(); -------------------------------------------------------------------------------- /04 Push Down Method/solution/Animal.js: -------------------------------------------------------------------------------- 1 | function Animal() { 2 | 3 | } -------------------------------------------------------------------------------- /04 Push Down Method/solution/Cat.js: -------------------------------------------------------------------------------- 1 | function Cat() { 2 | Animal.call(this); 3 | } 4 | Cat.prototype = new Animal(); -------------------------------------------------------------------------------- /04 Push Down Method/solution/Dog.js: -------------------------------------------------------------------------------- 1 | function Dog() { 2 | Animal.call(this); 3 | } 4 | Dog.prototype = new Animal(); 5 | Dog.prototype.bark = function () { 6 | // code to bark 7 | }; -------------------------------------------------------------------------------- /05 Pull Up Field/problem/Account.js: -------------------------------------------------------------------------------- 1 | function Account() { 2 | 3 | } -------------------------------------------------------------------------------- /05 Pull Up Field/problem/CheckingAccount.js: -------------------------------------------------------------------------------- 1 | function CheckingAccount() { 2 | Account.call(this); 3 | this.nMinimumCheckingBalance = 5; 4 | } 5 | CheckingAccount.prototype = new Account(); -------------------------------------------------------------------------------- /05 Pull Up Field/problem/SavingsAccount.js: -------------------------------------------------------------------------------- 1 | function SavingsAccount() { 2 | Account.call(this); 3 | this.nMinimumSavingsBalance = 5; 4 | } 5 | SavingsAccount.prototype = new Account(); -------------------------------------------------------------------------------- /05 Pull Up Field/solution/Account.js: -------------------------------------------------------------------------------- 1 | function Account() { 2 | this.nMinimumBalance = 5; 3 | } -------------------------------------------------------------------------------- /05 Pull Up Field/solution/CheckingAccount.js: -------------------------------------------------------------------------------- 1 | function CheckingAccount() { 2 | Account.call(this); 3 | } 4 | CheckingAccount.prototype = new Account(); -------------------------------------------------------------------------------- /05 Pull Up Field/solution/SavingsAccount.js: -------------------------------------------------------------------------------- 1 | function SavingsAccount() { 2 | Account.call(this); 3 | } 4 | SavingsAccount.prototype = new Account(); -------------------------------------------------------------------------------- /06 Push Down Field/problem/BugTask.js: -------------------------------------------------------------------------------- 1 | function BugTask() { 2 | Task.call(this); 3 | } 4 | BugTask.prototype = new Task(); -------------------------------------------------------------------------------- /06 Push Down Field/problem/FeatureTask.js: -------------------------------------------------------------------------------- 1 | function FeatureTask() { 2 | Task.call(this); 3 | } 4 | FeatureTask.prototype = new Task(); -------------------------------------------------------------------------------- /06 Push Down Field/problem/Task.js: -------------------------------------------------------------------------------- 1 | function Task() { 2 | this.sResolution = ''; 3 | } -------------------------------------------------------------------------------- /06 Push Down Field/solution/BugTask.js: -------------------------------------------------------------------------------- 1 | function BugTask() { 2 | Task.call(this); 3 | this.sResolution = ''; 4 | } 5 | BugTask.prototype = new Task(); -------------------------------------------------------------------------------- /06 Push Down Field/solution/FeatureTask.js: -------------------------------------------------------------------------------- 1 | function FeatureTask() { 2 | Task.call(this); 3 | } 4 | FeatureTask.prototype = new Task(); -------------------------------------------------------------------------------- /06 Push Down Field/solution/Task.js: -------------------------------------------------------------------------------- 1 | function Task() { 2 | 3 | } -------------------------------------------------------------------------------- /07 Rename (method, class, parameter)/problem/Person.js: -------------------------------------------------------------------------------- 1 | function Person() { 2 | this.sFN = ''; 3 | } 4 | Person.prototype.clcHrlyPR = function () { 5 | // code to calculate hourly payrate 6 | }; -------------------------------------------------------------------------------- /07 Rename (method, class, parameter)/solution/Employee.js: -------------------------------------------------------------------------------- 1 | function Employee() { 2 | this.sFirstName = ''; 3 | } 4 | Employee.prototype.calculateHourlyPay = function () { 5 | // code to calculate hourly payrate 6 | }; -------------------------------------------------------------------------------- /08 Replace Inheritance with Delegation/problem/Child.js: -------------------------------------------------------------------------------- 1 | function Child() { 2 | Sanitation.call(this); 3 | } 4 | Child.prototype = new Sanitation(); -------------------------------------------------------------------------------- /08 Replace Inheritance with Delegation/problem/Sanitation.js: -------------------------------------------------------------------------------- 1 | function Sanitation() { 2 | 3 | } 4 | Sanitation.prototype.washHands = function () { 5 | return 'Cleaned'; 6 | }; -------------------------------------------------------------------------------- /08 Replace Inheritance with Delegation/solution/Child.js: -------------------------------------------------------------------------------- 1 | function Child() { 2 | this.oSanitation = new Sanitation(); 3 | } 4 | Child.prototype.washHands = function () { 5 | return this.oSanitation.washHands(); 6 | } -------------------------------------------------------------------------------- /08 Replace Inheritance with Delegation/solution/Sanitation.js: -------------------------------------------------------------------------------- 1 | function Sanitation() { 2 | 3 | } 4 | Sanitation.prototype.washHands = function () { 5 | return 'Cleaned'; 6 | } -------------------------------------------------------------------------------- /09 Extract Interface/problem/ClassRegistration.js: -------------------------------------------------------------------------------- 1 | function ClassRegistration() { 2 | this.nTotal = 0; 3 | } 4 | ClassRegistration.prototype.create = function () { 5 | // create registration code 6 | }; 7 | ClassRegistration.prototype.transfer = function () { 8 | // class transfer code 9 | }; -------------------------------------------------------------------------------- /09 Extract Interface/problem/RegistrationProcessor.js: -------------------------------------------------------------------------------- 1 | function RegistrationProcessor() { 2 | 3 | } 4 | RegistrationProcessor.prototype.processRegistration = function (oClassRegistration) { 5 | oClassRegistration.create(); 6 | return oClassRegistration.nTotal; 7 | }; -------------------------------------------------------------------------------- /09 Extract Interface/solution/ClassRegistration.js: -------------------------------------------------------------------------------- 1 | function ClassRegistration() { 2 | InterfaceRegistration.call(this); 3 | } 4 | ClassRegistration.prototype = new InterfaceRegistration(); 5 | ClassRegistration.prototype.create = function () { 6 | // create registration code 7 | }; 8 | ClassRegistration.prototype.transfer = function () { 9 | // class transfer code 10 | }; -------------------------------------------------------------------------------- /09 Extract Interface/solution/InterfaceRegistration.js: -------------------------------------------------------------------------------- 1 | function InterfaceRegistration() { 2 | this.nTotal = 0; 3 | } 4 | InterfaceRegistration.prototype.create = function () { 5 | throw new Error('This method must be overwritten'); 6 | }; -------------------------------------------------------------------------------- /09 Extract Interface/solution/RegistrationProcessor.js: -------------------------------------------------------------------------------- 1 | function RegistrationProcessor() { 2 | 3 | } 4 | RegistrationProcessor.prototype.processRegistration = function (oRegistration) { 5 | oRegistration.create(); 6 | return oRegistration.nTotal; 7 | }; -------------------------------------------------------------------------------- /10 Extract Method/problem/Receipt.js: -------------------------------------------------------------------------------- 1 | function Receipt() { 2 | this.aDiscounts = []; 3 | this.aItemTotals = []; 4 | } 5 | Receipt.prototype.calculateGrandTotal = function () { 6 | var nSubTotal = 0, 7 | nTax, 8 | nTotal, 9 | nLenTotals = this.aItemTotals.length, 10 | nItemValue, 11 | nDiscount, 12 | nLenDiscounts = this.aDiscounts.length, 13 | nDiscountValue; 14 | for (nTotal = 0; nTotal < nLenTotals; nTotal++) { 15 | nItemValue = this.aItemTotals[nTotal]; 16 | nSubTotal += nItemValue; 17 | } 18 | if (nLenDiscounts > 0) { 19 | for (nDiscount = 0; nDiscount < nLenDiscounts; nDiscount++) { 20 | nDiscountValue = this.aDiscounts[nDiscount]; 21 | nSubTotal -= nDiscountValue; 22 | } 23 | } 24 | nTax = nSubTotal * 0.065; 25 | nSubTotal += nTax; 26 | return nSubTotal 27 | }; -------------------------------------------------------------------------------- /10 Extract Method/solution/Receipt.js: -------------------------------------------------------------------------------- 1 | function Receipt() { 2 | this.aDiscounts = []; 3 | this.aItemTotals = []; 4 | } 5 | Receipt.prototype.calculateGrandTotal = function () { 6 | var nSubTotal = this.calculateSubtotal(); 7 | nSubTotal = this.calculateDiscounts(nSubTotal); 8 | nSubTotal = this.calculateTax(nSubTotal); 9 | return nSubTotal; 10 | }; 11 | Receipt.prototype.calculateTax = function (nSubTotal) { 12 | var nTax = nSubTotal * 0.065; 13 | nSubTotal += nTax; 14 | return nSubTotal; 15 | }; 16 | Receipt.prototype.calculateDiscounts = function (nSubTotal) { 17 | var nDiscount, 18 | nLenDiscounts = this.aDiscounts.length, 19 | nDiscountValue; 20 | if (nLenDiscounts) { 21 | for (nDiscount = 0; nDiscount < nLenDiscounts; nDiscount++) { 22 | nDiscountValue = this.aDiscounts[nDiscount]; 23 | nSubTotal -= nDiscountValue; 24 | } 25 | } 26 | return nSubTotal; 27 | }; 28 | Receipt.prototype.calculateSubtotal = function () { 29 | var nSubTotal = 0, 30 | nTotal, 31 | nLenTotals = this.aItemTotals.length, 32 | nItemValue; 33 | for (nTotal = 0; nTotal < nLenTotals; nTotal++) { 34 | nItemValue = this.aItemTotals[nTotal]; 35 | nSubTotal += nItemValue; 36 | } 37 | return nSubTotal; 38 | }; -------------------------------------------------------------------------------- /11 Switch to Strategy/problem/switch.js: -------------------------------------------------------------------------------- 1 | (function (ns) { 2 | var oNamespace; 3 | ns.DaysOfRefactoring = {}; 4 | ns.DaysOfRefactoring.SwitchToStrategy = {}; 5 | ns.DaysOfRefactoring.SwitchToStrategy.Before = {}; 6 | oNamespace = ns.DaysOfRefactoring.SwitchToStrategy.Before; 7 | oNamespace.oState = { 8 | Alaska:0, 9 | NewYork:1, 10 | Florida:2 11 | }; 12 | oNamespace.ShippingInfo = function () { 13 | 14 | }; 15 | oNamespace.ShippingInfo.prototype.calculateShippingAmount = function (nState) { 16 | switch (nState) { 17 | case oNamespace.oState.Alaska: 18 | return this.getAlaskaShippingAmount(); 19 | case oNamespace.oState.NewYork: 20 | return this.getNewYorkShippingAmount(); 21 | case oNamespace.oState.Florida: 22 | return this.getFloridaShippingAmount(); 23 | default: 24 | return 0; 25 | } 26 | }; 27 | oNamespace.ShippingInfo.prototype.getAlaskaShippingAmount = function () { 28 | return 15; 29 | }; 30 | oNamespace.ShippingInfo.prototype.getNewYorkShippingAmount = function () { 31 | return 10; 32 | }; 33 | oNamespace.ShippingInfo.prototype.getFloridaShippingAmount = function () { 34 | return 3; 35 | }; 36 | oNamespace.ClientCode = function () { 37 | 38 | }; 39 | oNamespace.ClientCode.prototype.calculateShippingAmount = function () { 40 | var shippingInfo = new oNamespace.ShippingInfo(); 41 | return shippingInfo.calculateShippingAmount(oNamespace.oState.Alaska); 42 | }; 43 | }(Namespace)); -------------------------------------------------------------------------------- /11 Switch to Strategy/solution/switch.js: -------------------------------------------------------------------------------- 1 | (function (ns) { 2 | var oNamespace; 3 | ns.DaysOfRefactoring = {}; 4 | ns.DaysOfRefactoring.SwitchToStrategy = {}; 5 | ns.DaysOfRefactoring.SwitchToStrategy.After = {}; 6 | oNamespace = ns.DaysOfRefactoring.SwitchToStrategy.After; 7 | oNamespace.oState = { 8 | Alaska:0, 9 | NewYork:1, 10 | Florida:2 11 | }; 12 | oNamespace.InterfaceCalculation = function () { 13 | 14 | }; 15 | oNamespace.InterfaceCalculation.prototype.calculate = function () { 16 | throw new Error('This method must be overwritten!'); 17 | }; 18 | oNamespace.AlaskaShippingCalculation = function () { 19 | oNamespace.InterfaceCalculation.call(this); 20 | }; 21 | oNamespace.AlaskaShippingCalculation.prototype = new oNamespace.InterfaceCalculation(); 22 | oNamespace.AlaskaShippingCalculation.prototype.calculate = function () { 23 | return 15; 24 | }; 25 | oNamespace.NewYorkShippingCalculation = function () { 26 | oNamespace.InterfaceCalculation.call(this); 27 | }; 28 | oNamespace.NewYorkShippingCalculation.prototype = new oNamespace.InterfaceCalculation(); 29 | oNamespace.NewYorkShippingCalculation.prototype.calculate = function () { 30 | return 10; 31 | }; 32 | oNamespace.FloridaShippingCalculation = function () { 33 | oNamespace.InterfaceCalculation.call(this); 34 | }; 35 | oNamespace.FloridaShippingCalculation.prototype = new oNamespace.InterfaceCalculation(); 36 | oNamespace.FloridaShippingCalculation.prototype.calculate = function () { 37 | return 3; 38 | }; 39 | oNamespace.ShippingInfo = function () { 40 | var oState = oNamespace.oState; 41 | this.oShippingCalculations = {}; 42 | this.oShippingCalculations[oState.Alaska] = new oNamespace.AlaskaShippingCalculation(); 43 | this.oShippingCalculations[oState.NewYork] = new oNamespace.NewYorkShippingCalculation(); 44 | this.oShippingCalculations[oState.Florida] = new oNamespace.FloridaShippingCalculation(); 45 | }; 46 | oNamespace.ShippingInfo.prototype.calculateShippingAmount = function (nShippingState) { 47 | return this.oShippingCalculations[nShippingState].calculate(); 48 | }; 49 | oNamespace.ClientCode = function () { 50 | 51 | }; 52 | oNamespace.ClientCode.prototype.calculateShipping = function () { 53 | var oNamespace = ns.DaysOfRefactoring.SwitchToStrategy.Before, 54 | shippingInfo = new oNamespace.ShippingInfo(); 55 | return shippingInfo.calculateShippingAmount(oNamespace.oState.Alaska); 56 | }; 57 | 58 | }(Namespace)); -------------------------------------------------------------------------------- /11 Switch to Strategy/solution/switch2.js: -------------------------------------------------------------------------------- 1 | (function (ns) { 2 | var oNamespace; 3 | ns.DaysOfRefactoring = {}; 4 | ns.DaysOfRefactoring.SwitchToStrategy = {}; 5 | ns.DaysOfRefactoring.SwitchToStrategy.After = {}; 6 | oNamespace = ns.DaysOfRefactoring.SwitchToStrategy.After; 7 | oNamespace.aState = [ 'Alaska', 'NewYork', 'Florida']; 8 | oNamespace.InterfaceShippingInfo = function () { 9 | 10 | }; 11 | oNamespace.InterfaceShippingInfo.prototype.calculateShippingAmount = function (nState) { 12 | throw new Error('This method must be overwritten'); 13 | }; 14 | oNamespace.InterfaceShippingCalculation = function () { 15 | 16 | }; 17 | oNamespace.InterfaceShippingCalculation.prototype.calculate = function () { 18 | throw new Error('This method must be overwritten'); 19 | }; 20 | oNamespace.ClientCode = function (oShippingInfo) { 21 | this.oShippingInfo = oShippingInfo; 22 | }; 23 | oNamespace.ClientCode.prototype.calculateShipping = function () { 24 | this.oShippingInfo.calculateShippingAmount(oNamespace.aState[0]); 25 | }; 26 | oNamespace.ShippingInfo = function () { 27 | oNamespace.InterfaceShippingInfo.call(this); 28 | }; 29 | oNamespace.ShippingInfo.prototype = new oNamespace.InterfaceCalculation(); 30 | oNamespace.ShippingInfo.calculateShippingAmount = function (sState) { 31 | return new oNamespace[sState + 'ShippingCalculation']().calculate(); 32 | }; 33 | oNamespace.AlaskaShippingCalculation = function () { 34 | oNamespace.InterfaceShippingCalculation.call(this); 35 | }; 36 | oNamespace.AlaskaShippingCalculation.prototype = new oNamespace.InterfaceShippingCalculation(); 37 | oNamespace.AlaskaShippingCalculation.prototype.calculate = function () { 38 | return 15; 39 | }; 40 | oNamespace.NewYorkShippingCalculation = function () { 41 | oNamespace.InterfaceShippingCalculation.call(this); 42 | }; 43 | oNamespace.NewYorkShippingCalculation.prototype = new oNamespace.InterfaceShippingCalculation(); 44 | oNamespace.NewYorkShippingCalculation.prototype.calculate = function () { 45 | return 10; 46 | }; 47 | oNamespace.FloridaShippingCalculation = function () { 48 | oNamespace.InterfaceShippingCalculation.call(this); 49 | }; 50 | oNamespace.FloridaShippingCalculation.prototype = new oNamespace.InterfaceShippingCalculation(); 51 | oNamespace.FloridaShippingCalculation.prototype.calculate = function () { 52 | return 3; 53 | }; 54 | }(Namespace)); -------------------------------------------------------------------------------- /12 Break Dependencies/problem/AnimalFeedingService.js: -------------------------------------------------------------------------------- 1 | function AnimalFeedingService() { 2 | this.bFoodBoolEmpty = true; 3 | } 4 | AnimalFeedingService.prototype.feed = function () { 5 | if (this.bFoodBoolEmpty) { 6 | Feeder.replenishFood(); 7 | } 8 | // more code to feed the animal 9 | }; -------------------------------------------------------------------------------- /12 Break Dependencies/problem/Feeder.js: -------------------------------------------------------------------------------- 1 | function Feeder() { 2 | 3 | } 4 | Feeder.replenishFood = function () { 5 | // fill up bowl 6 | }; -------------------------------------------------------------------------------- /12 Break Dependencies/solution/AnimalFeedingService.js: -------------------------------------------------------------------------------- 1 | function AnimalFeedingService(oFeederService) { 2 | this.oFeederService = oFeederService; 3 | this.bFoodBoolEmpty = true; 4 | } 5 | AnimalFeedingService.prototype.feed = function () { 6 | if (this.bFoodBoolEmpty) { 7 | this.oFeederService.replenishFood(); 8 | } 9 | // more code to feed the animal 10 | }; -------------------------------------------------------------------------------- /12 Break Dependencies/solution/Feeder.js: -------------------------------------------------------------------------------- 1 | function Feeder() { 2 | 3 | } 4 | Feeder.replenishFood = function () { 5 | // fill up bowl 6 | }; -------------------------------------------------------------------------------- /12 Break Dependencies/solution/FeederService.js: -------------------------------------------------------------------------------- 1 | function FeederService() { 2 | InterfaceFeederService.call(this); 3 | } 4 | FeederService.prototype = new FeederService(); 5 | FeederService.prototype.replenishFood = function () { 6 | Feeder.replenishFood(); 7 | }; -------------------------------------------------------------------------------- /12 Break Dependencies/solution/InterfaceFeederService.js: -------------------------------------------------------------------------------- 1 | function InterfaceFeederService() { 2 | 3 | } 4 | InterfaceFeederService.prototype.replenishFood = function () { 5 | throw new Error('This method must be overwritten'); 6 | }; -------------------------------------------------------------------------------- /13 Extract Method Object/problem/Order.js: -------------------------------------------------------------------------------- 1 | function Order() { 2 | this.aOrderLineItems = []; 3 | this.aDiscounts = []; 4 | this.nTax = 0; 5 | } 6 | Order.prototype.calculate = function () { 7 | var nSubTotal = 0, 8 | nLineItem, 9 | nLenLineItems = this.aOrderLineItems.length, 10 | nItemValue, 11 | nDiscount, 12 | nLenDiscounts = this.aDiscounts.length, 13 | nDiscountValue, 14 | nTax, 15 | nGrandTotal; 16 | for (nLineItem = 0; nLineItem < nLenLineItems; nLineItem++) { 17 | nItemValue = this.aOrderLineItems[nLineItem]; 18 | nSubTotal += nItemValue; 19 | } 20 | for (nDiscount = 0; nDiscount < nLenDiscounts; nDiscount++) { 21 | nDiscountValue = this.aDiscounts[nDiscount]; 22 | nSubTotal -= nDiscountValue; 23 | } 24 | nTax = nSubTotal * this.nTax; 25 | nGrandTotal = nSubTotal + nTax; 26 | return nGrandTotal; 27 | }; -------------------------------------------------------------------------------- /13 Extract Method Object/problem/OrderLineItem.js: -------------------------------------------------------------------------------- 1 | function OrderLineItem() { 2 | this.nPrice = 0; 3 | } -------------------------------------------------------------------------------- /13 Extract Method Object/solution/Order.js: -------------------------------------------------------------------------------- 1 | function Order() { 2 | this.aOrderLineItems = []; 3 | this.aDiscounts = []; 4 | this.nTax = 0; 5 | } 6 | Order.prototype.calculate = function () { 7 | return new OrderCalculator(this).calculate(); 8 | }; -------------------------------------------------------------------------------- /13 Extract Method Object/solution/OrderCalculator.js: -------------------------------------------------------------------------------- 1 | function OrderCalculator(oOrder) { 2 | this.nSubTotal = 0; 3 | this.aOrderLineItems = oOrder.aOrderLineItems; 4 | this.aDiscounts = oOrder.aDiscounts; 5 | this.nTax = oOrder.nTax; 6 | } 7 | OrderCalculator.prototype.calculate = function () { 8 | this.calculateSubTotal(); 9 | this.substractDiscounts(); 10 | this.calculateTax(); 11 | return this.nSubTotal; 12 | }; 13 | OrderCalculator.prototype.calculateSubTotal = function () { 14 | var nLineItem, 15 | nLenLineItems = this.aOrderLineItems, 16 | nItemValue; 17 | for (nLineItem = 0; nLineItem < nLenLineItems; nLineItem++) { 18 | nItemValue = this.aOrderLineItems[nLineItem]; 19 | this.nSubTotal += nItemValue; 20 | } 21 | }; 22 | OrderCalculator.prototype.substractDiscounts = function () { 23 | var nDiscount, 24 | nLenDiscounts = this.aDiscounts.length, 25 | nDiscountValue; 26 | for (nDiscount = 0; nDiscount < nLenDiscounts; nDiscount++) { 27 | nDiscountValue = this.aDiscounts[nDiscount]; 28 | this.nSubTotal -= nDiscountValue; 29 | } 30 | }; 31 | OrderCalculator.prototype.calculateTax = function () { 32 | this.nSubTotal += this.nSubTotal * this.nTax; 33 | }; -------------------------------------------------------------------------------- /13 Extract Method Object/solution/OrderLineItem.js: -------------------------------------------------------------------------------- 1 | function OrderLineItem() { 2 | this.nPrice = 0; 3 | } -------------------------------------------------------------------------------- /14 Break Responsibilities/problem/Customer.js: -------------------------------------------------------------------------------- 1 | function Customer() { 2 | this.aLateFees = []; 3 | this.aVideos = []; 4 | } -------------------------------------------------------------------------------- /14 Break Responsibilities/problem/Video.js: -------------------------------------------------------------------------------- 1 | function Video() { 2 | 3 | } 4 | Video.prototype.payFee = function (nFee) { 5 | 6 | }; 7 | Video.prototype.rentVideo = function (oVideo, oCustomer) { 8 | oCustomer.aVideos.push(oVideo); 9 | }; 10 | Video.prototype.calculateBalance = function (oCustomer) { 11 | return oCustomer.aLateFees.sum(); 12 | }; -------------------------------------------------------------------------------- /14 Break Responsibilities/solution/Customer.js: -------------------------------------------------------------------------------- 1 | function Customer() { 2 | this.aLateFees = []; 3 | this.aVideos = []; 4 | } 5 | Customer.prototype.payFee = function () { 6 | 7 | }; 8 | Customer.prototype.calculateBalance = function (oCustomer) { 9 | return oCustomer.aLateFees.sum(); 10 | }; -------------------------------------------------------------------------------- /14 Break Responsibilities/solution/Video.js: -------------------------------------------------------------------------------- 1 | function Video() { 2 | 3 | } 4 | Video.prototype.rentVideo = function (oVideo, oCustomer) { 5 | oCustomer.aVideos.push(oVideo); 6 | }; -------------------------------------------------------------------------------- /15 Remove Duplication/problem/MedicalRecord.js: -------------------------------------------------------------------------------- 1 | function MedicalRecord() { 2 | this.dDateArchived = null; 3 | this.bArchived = false; 4 | } 5 | MedicalRecord.prototype.archiveRecord = function () { 6 | this.bArchived = true; 7 | this.dDateArchived = Date.now(); 8 | }; 9 | MedicalRecord.prototype.closeRecord = function () { 10 | this.bArchived = true; 11 | this.dDateArchived = Date.now(); 12 | }; -------------------------------------------------------------------------------- /15 Remove Duplication/solution/MedicalRecord.js: -------------------------------------------------------------------------------- 1 | function MedicalRecord() { 2 | this.dDateArchived = null; 3 | this.bArchived = false; 4 | } 5 | MedicalRecord.prototype.archiveRecord = function () { 6 | this._switchToArchived(); 7 | }; 8 | MedicalRecord.prototype.closeRecord = function () { 9 | this._switchToArchived(); 10 | }; 11 | MedicalRecord.prototype._switchToArchived = function () { 12 | this.bArchived = true; 13 | this.dDateArchived = Date.now(); 14 | }; -------------------------------------------------------------------------------- /16 Encapsulate Conditional/problem/RemoteControl.js: -------------------------------------------------------------------------------- 1 | function RemoteControl() { 2 | this.aFunctions = []; 3 | this.sName = ''; 4 | this.nCreatedYear = 0; 5 | } 6 | RemoteControl.prototype.performCoolFunction = function (sButtonPressed) { 7 | if (this.aFunctions.length > 1 && this.sName === "RCA" && this.nCreatedYear > Date.now().getFullYear() - 2) { 8 | return 'doSomething'; 9 | } 10 | }; -------------------------------------------------------------------------------- /16 Encapsulate Conditional/solution/RemoteControl.js: -------------------------------------------------------------------------------- 1 | function RemoteControl() { 2 | this.aFunctions = []; 3 | this.sName = ''; 4 | this.nCreatedYear = 0; 5 | } 6 | RemoteControl.prototype.hasExtraFunctions = function () { 7 | return this.aFunctions.length > 1 && this.sName === 'RCA' && this.nCreatedYear > Date.now().getFullYear() - 2; 8 | }; 9 | RemoteControl.prototype.performCoolFunction = function () { 10 | if (this.hasExtraFunctions()) { 11 | return 'doSomething'; 12 | } 13 | }; -------------------------------------------------------------------------------- /17 Extract Superclass/problem/Dog.js: -------------------------------------------------------------------------------- 1 | function Dog() { 2 | 3 | } 4 | Dog.prototype.eatFood = function () { 5 | // eat some food 6 | }; 7 | Dog.prototype.groom = function () { 8 | // perform grooming 9 | }; -------------------------------------------------------------------------------- /17 Extract Superclass/solution/Animal.js: -------------------------------------------------------------------------------- 1 | function Animal() { 2 | 3 | } 4 | Animal.prototype.eatFood = function () { 5 | // eat some food 6 | }; 7 | Animal.prototype.groom = function () { 8 | // perform grooming 9 | }; -------------------------------------------------------------------------------- /17 Extract Superclass/solution/Dog.js: -------------------------------------------------------------------------------- 1 | function Dog() { 2 | Animal.call(this); 3 | } 4 | Dog.prototype = new Animal(); -------------------------------------------------------------------------------- /18 Replace exception with conditional/problem/Microwave.js: -------------------------------------------------------------------------------- 1 | function Microwave(oMicrowaveMotor) { 2 | this.oMicrowaveMotor = oMicrowaveMotor; 3 | } 4 | Microwave.prototype.start = function (oFood) { 5 | var bFoodCooked = false; 6 | try { 7 | this.oMicrowaveMotor.cook(oFood); 8 | bFoodCooked = true; 9 | } 10 | catch (erError) { 11 | bFoodCooked = false; 12 | } 13 | return bFoodCooked; 14 | }; -------------------------------------------------------------------------------- /18 Replace exception with conditional/problem/MicrowaveMotor.js: -------------------------------------------------------------------------------- 1 | function MicrowaveMotor() 2 | { 3 | } 4 | MicrowaveMotor.prototype.cook = function(oFood) 5 | { 6 | console.log(oFood, 'is cooking'); 7 | console.log(oFood, 'is cooked'); 8 | }; -------------------------------------------------------------------------------- /18 Replace exception with conditional/solution/Microwave.js: -------------------------------------------------------------------------------- 1 | function Microwave(oMicrowaveMotor) { 2 | this.oMicrowaveMotor = oMicrowaveMotor; 3 | } 4 | Microwave.prototype.start = function (oFood) { 5 | if (this.oMicrowaveMotor.isInUse()) { 6 | return false; 7 | } 8 | this.oMicrowaveMotor.cook(oFood); 9 | return true; 10 | }; -------------------------------------------------------------------------------- /18 Replace exception with conditional/solution/MicrowaveMotor.js: -------------------------------------------------------------------------------- 1 | function MicrowaveMotor() 2 | { 3 | this.bCooking = false; 4 | } 5 | MicrowaveMotor.prototype.isInUse = function() 6 | { 7 | return this.bCooking; 8 | }; 9 | MicrowaveMotor.prototype.cook = function(oFood) 10 | { 11 | this.bCooking = true; 12 | console.log(oFood, 'is cooking'); 13 | console.log(oFood, 'is cooked'); 14 | this.bCooking = false; 15 | }; -------------------------------------------------------------------------------- /19 Extract Factory Class/problem/PoliceCarController.js: -------------------------------------------------------------------------------- 1 | function PoliceCarController(nMileage, bServiceRequired) { 2 | } 3 | PoliceCarController.prototype.getCar = function (nMileage, bServiceRequired) { 4 | var oPoliceCar = new PoliceCar(); 5 | oPoliceCar.bServiceRequired = bServiceRequired; 6 | oPoliceCar.nMileage = nMileage; 7 | return oPoliceCar; 8 | }; -------------------------------------------------------------------------------- /19 Extract Factory Class/solution/InterfacePoliceCarFactory.js: -------------------------------------------------------------------------------- 1 | function InterfacePoliceCarFactory() { 2 | 3 | } 4 | InterfacePoliceCarFactory.prototype.create = function () { 5 | throw new Error(); 6 | }; -------------------------------------------------------------------------------- /19 Extract Factory Class/solution/PoliceCarController.js: -------------------------------------------------------------------------------- 1 | function PoliceCarController(oPoliceCarFactory) { 2 | this.oPoliceCarFactory = oPoliceCarFactory; 3 | } 4 | PoliceCarController.prototype.getCar = function (nMileage, bServiceRequired) { 5 | return this.oPoliceCarFactory.create(nMileage, bServiceRequired); 6 | }; -------------------------------------------------------------------------------- /19 Extract Factory Class/solution/PoliceCarFactory.js: -------------------------------------------------------------------------------- 1 | function PoliceCarFactory() { 2 | InterfacePoliceCarFactory.call(this); 3 | } 4 | PoliceCarFactory.prototype = new InterfacePoliceCarFactory(); 5 | PoliceCarFactory.create = function (nMileage, bServiceRequired) { 6 | var oPoliceCar = new PoliceCar(); 7 | oPoliceCar.readForService = bServiceRequired; 8 | oPoliceCar.nMileage = nMileage; 9 | return oPoliceCar; 10 | }; -------------------------------------------------------------------------------- /20 Extract SubClass/problem/Registration.js: -------------------------------------------------------------------------------- 1 | function Registration() { 2 | this.oNonRegistrationAction = null; 3 | this.nRegistrationTotal = 0; 4 | this.sNotes = ''; 5 | this.sDescription = ''; 6 | this.dRegistrationDate = 0; 7 | } 8 | -------------------------------------------------------------------------------- /20 Extract SubClass/solution/NonRegistration.js: -------------------------------------------------------------------------------- 1 | function NonRegistration() { 2 | Registration.call(this); 3 | this.oNonRegistrationAction = null; 4 | this.sNotes = ''; 5 | } 6 | NonRegistration.prototype = new Registration(); -------------------------------------------------------------------------------- /20 Extract SubClass/solution/Registration.js: -------------------------------------------------------------------------------- 1 | function Registration() { 2 | this.nRegistrationTotal = 0; 3 | this.sDescription = ''; 4 | this.dRegistrationDate = 0; 5 | } -------------------------------------------------------------------------------- /21 Collapse Hierarchy/problem/StudentWebsite.js: -------------------------------------------------------------------------------- 1 | function StudentWebsite() { 2 | Website.call(this); 3 | this.bActive = false; 4 | } 5 | StudentWebsite.prototype = new Website(); -------------------------------------------------------------------------------- /21 Collapse Hierarchy/problem/Website.js: -------------------------------------------------------------------------------- 1 | function Website() { 2 | this.sTitle = ''; 3 | this.sDescription = ''; 4 | this.aPages = []; 5 | } -------------------------------------------------------------------------------- /21 Collapse Hierarchy/solution/Website.js: -------------------------------------------------------------------------------- 1 | function Website() { 2 | this.sTitle = ''; 3 | this.sDescription = ''; 4 | this.aPages = []; 5 | this.bIsActive = false; 6 | } 7 | -------------------------------------------------------------------------------- /22 Break Method/problem/CashRegister.js: -------------------------------------------------------------------------------- 1 | function CashRegister() { 2 | this.nTax = 0.06; 3 | } 4 | CashRegister.prototype.acceptPayment = function (oCustomer, aProducts, nPayment) { 5 | var nSubTotal = 0, 6 | nProduct, 7 | nGrandTotal, 8 | nLenProduct = aProducts.length, 9 | oProduct; 10 | for (nProduct = 0; nProduct < nLenProduct; nProduct++) { 11 | oProduct = aProducts[nProduct]; 12 | nSubTotal += oProduct.nPrice; 13 | } 14 | for (nProduct = 0; nProduct < nLenProduct; nProduct++) { 15 | oProduct = aProducts[nProduct]; 16 | nSubTotal -= oProduct.nAvailableDiscounts; 17 | } 18 | nGrandTotal = nSubTotal * this.nTax; 19 | oCustomer.deductFromAccountBalance(nGrandTotal); 20 | }; -------------------------------------------------------------------------------- /22 Break Method/problem/Customer.js: -------------------------------------------------------------------------------- 1 | function Customer() { 2 | 3 | } 4 | Customer.prototype.deductFromAccountBalance = function (nAmount) { 5 | // deduct from balance. 6 | }; -------------------------------------------------------------------------------- /22 Break Method/problem/Product.js: -------------------------------------------------------------------------------- 1 | function Product() { 2 | this.nPrice = 0; 3 | this.nAvailableDiscounts = 0; 4 | } -------------------------------------------------------------------------------- /22 Break Method/solution/CashRegister.js: -------------------------------------------------------------------------------- 1 | function CashRegister() { 2 | this.nTax = 0.06; 3 | this.aProducts = []; 4 | } 5 | CashRegister.prototype.acceptPayment = function (oCustomer, aProducts, nPayment) { 6 | var nSubTotal = this.calculateSubTotal(), 7 | nGrandTotal; 8 | nSubTotal = this.substractDiscounts(nSubTotal); 9 | nGrandTotal = this.addTax(nSubTotal); 10 | this.substractFromCustomerBalance(oCustomer, nGrandTotal); 11 | }; 12 | CashRegister.prototype.substractFromCustomerBalance = function (oCustomer, nGrandTotal) { 13 | oCustomer.deductFromAccountBalance(nGrandTotal); 14 | }; 15 | CashRegister.prototype.addTax = function (nSubTotal) { 16 | return nSubTotal + this.nTax; 17 | }; 18 | CashRegister.prototype.substractDiscounts = function (nSubTotal) { 19 | var nProduct, 20 | nLenProduct = this.aProducts.length, 21 | oProduct; 22 | for (nProduct = 0; nProduct < nLenProduct; nProduct++) { 23 | oProduct = this.aProducts[nProduct]; 24 | nSubTotal -= oProduct.nAvailableDiscounts; 25 | } 26 | return nSubTotal; 27 | }; 28 | CashRegister.prototype.calculateSubTotal = function () { 29 | var nSubTotal = 0, 30 | nProduct, 31 | nLenProduct = this.aProducts.length, 32 | oProduct; 33 | for (nProduct = 0; nProduct < nLenProduct; nProduct++) { 34 | oProduct = this.aProducts[nProduct]; 35 | nSubTotal += oProduct.nPrice; 36 | } 37 | return nSubTotal; 38 | } -------------------------------------------------------------------------------- /22 Break Method/solution/Customer.js: -------------------------------------------------------------------------------- 1 | function Customer() { 2 | 3 | } 4 | Customer.prototype.deductFromAccountBalance = function (nAmount) { 5 | // deduct from balance. 6 | }; -------------------------------------------------------------------------------- /22 Break Method/solution/Product.js: -------------------------------------------------------------------------------- 1 | function Product() { 2 | this.nPrice = 0; 3 | this.nAvailableDiscounts = 0; 4 | } -------------------------------------------------------------------------------- /23 Introduce Parameter Object/problem/Registration.js: -------------------------------------------------------------------------------- 1 | function Registration() { 2 | 3 | } 4 | Registration.prototype.create = function (nAmount, oStudent, aCourses, nCredits) { 5 | // do work 6 | }; -------------------------------------------------------------------------------- /23 Introduce Parameter Object/solution/Registration.js: -------------------------------------------------------------------------------- 1 | function Registration() { 2 | 3 | } 4 | Registration.prototype.create = function (oRegistrationContext) { 5 | // do work 6 | }; -------------------------------------------------------------------------------- /23 Introduce Parameter Object/solution/RegistrationContext.js: -------------------------------------------------------------------------------- 1 | function RegistrationContext() { 2 | this.nAmount = 0; 3 | this.oStudent = null; 4 | this.aCourses = []; 5 | this.nCredits = 0; 6 | } -------------------------------------------------------------------------------- /24 Remove Arrowhead Antipattern/problem/Security.js: -------------------------------------------------------------------------------- 1 | function Security(oSecurityChecker) { 2 | this.oSecurityChecker = oSecurityChecker; 3 | } 4 | Security.prototype.hasAccess = function (oUser, oPermission, aExcemptions) { 5 | var bPermission = false; 6 | if (oUser !== null) { 7 | if (oPermission !== null) { 8 | if (aExcemptions.length === 0) { 9 | if (this.oSecurityChecker.checkPermission(oUser, oPermission, aExcemptions)) { 10 | bPermission = true; 11 | } 12 | } 13 | } 14 | } 15 | return bPermission; 16 | }; -------------------------------------------------------------------------------- /24 Remove Arrowhead Antipattern/solution/Security.js: -------------------------------------------------------------------------------- 1 | function Security(oSecurityChecker) { 2 | this.oSecurityChecker = oSecurityChecker; 3 | } 4 | Security.prototype.hasAccess = function (oUser, oPermission, aExcemptions) { 5 | if (oUser === null || oPermission === null) { 6 | return false; 7 | } 8 | if (aExcemptions.contains(oPermission)) { 9 | return true; 10 | } 11 | return this.oSecurityChecker.checkHasPermission(oUser, oPermission); 12 | }; -------------------------------------------------------------------------------- /25 Introduce Design By Contract checks/problem/CashRegister.js: -------------------------------------------------------------------------------- 1 | function CashRegister() { 2 | 3 | } 4 | CashRegister.prototype.totalOrder = function (aProducts, oCustomer) { 5 | var nOrderTotal = aProducts.sum('nPrice'); 6 | oCustomer.nBalance += nOrderTotal; 7 | return nOrderTotal; 8 | }; -------------------------------------------------------------------------------- /25 Introduce Design By Contract checks/solution/CashRegister.js: -------------------------------------------------------------------------------- 1 | function CashRegister() { 2 | 3 | } 4 | CashRegister.prototype.totalOrder = function (aProducts, oCustomer) { 5 | var nTotalOrder = 0; 6 | if (oCustomer === null) { 7 | throw new Error('Customer can not be null'); 8 | } 9 | if (aProducts.length === 0) { 10 | throw new Error('Must have at least one product to total'); 11 | } 12 | nTotalOrder = aProducts.sum(); 13 | if (nTotalOrder === 0) { 14 | throw new Error('Order Total should not be zero'); 15 | } 16 | return nTotalOrder; 17 | }; -------------------------------------------------------------------------------- /26 Remove Double Negative/problem/Customer.js: -------------------------------------------------------------------------------- 1 | function Customer() { 2 | this.nBalance = 0; 3 | } 4 | Customer.prototype.isNotFlagged = function () { 5 | return this.nBalance < 30; 6 | }; -------------------------------------------------------------------------------- /26 Remove Double Negative/problem/Order.js: -------------------------------------------------------------------------------- 1 | function Order() { 2 | 3 | } 4 | Order.prototype.checkout = function (aProducts, oCustomer) { 5 | if (!oCustomer.isNotFlagged()) { 6 | // the customer account is flagged 7 | // log some errors and return 8 | return; 9 | } 10 | // normal order processing 11 | }; -------------------------------------------------------------------------------- /26 Remove Double Negative/solution/Customer.js: -------------------------------------------------------------------------------- 1 | function Customer() { 2 | this.nBalance = 0; 3 | } 4 | Customer.prototype.isFlagged = function () { 5 | return this.nBalance >= 30; 6 | }; -------------------------------------------------------------------------------- /26 Remove Double Negative/solution/Order.js: -------------------------------------------------------------------------------- 1 | function Order() { 2 | 3 | } 4 | Order.prototype.checkout = function (aProducts, oCustomer) { 5 | if (oCustomer.isFlagged()) { 6 | // the customer account is flagged 7 | // log some errors and return 8 | return; 9 | } 10 | // normal order processing 11 | }; -------------------------------------------------------------------------------- /27 Remove God Classes/problem/CustomerService.js: -------------------------------------------------------------------------------- 1 | function CustomerService() { 2 | 3 | } 4 | CustomerService.prototype.calculateOrderDiscount = function (aProducts, oCustomer) { 5 | // do work 6 | }; 7 | CustomerService.prototype.isValidCustomer = function (oCustomer, oOrder) { 8 | // do work 9 | }; 10 | CustomerService.prototype.gatherOrderErrors = function (aProducts, oCustomer) { 11 | // do work 12 | }; 13 | CustomerService.prototype.register = function (oCustomer) { 14 | // do work 15 | }; 16 | CustomerService.prototype.forgotPassword = function (oCustomer) { 17 | // do work 18 | }; -------------------------------------------------------------------------------- /27 Remove God Classes/solution/CustomerOrderService.js: -------------------------------------------------------------------------------- 1 | function CustomerOrderService() { 2 | 3 | } 4 | CustomerOrderService.prototype.calculateOrderDiscount = function (aProducts, oCustomer) { 5 | // do work 6 | }; 7 | CustomerOrderService.prototype.isValidCustomer = function (oCustomer, oOrder) { 8 | // do work 9 | }; 10 | CustomerOrderService.prototype.gatherOrderErrors = function (aProducts, oCustomer) { 11 | // do work 12 | }; -------------------------------------------------------------------------------- /27 Remove God Classes/solution/CustomerRegistrationService.js: -------------------------------------------------------------------------------- 1 | function CustomerRegistrationService() { 2 | 3 | } 4 | CustomerRegistrationService.prototype.register = function () { 5 | // do work 6 | }; 7 | CustomerRegistrationService.prototype.forgotPassword = function () { 8 | // do work 9 | }; 10 | -------------------------------------------------------------------------------- /28 Rename boolean method/problem/BankAccount.js: -------------------------------------------------------------------------------- 1 | function BankAccount() { 2 | 3 | } 4 | BankAccount.prototype.createAccount = function (oCustomer, bWithChecking, bWithSavings, bWithStocks) { 5 | // do work 6 | }; -------------------------------------------------------------------------------- /28 Rename boolean method/solution/BankAccount.js: -------------------------------------------------------------------------------- 1 | function BankAccount() { 2 | 3 | } 4 | BankAccount.prototype.createAccountWithChecking = function (oCustomer) { 5 | this.createAccount(oCustomer, true, false); 6 | }; 7 | BankAccount.prototype.createAccountWithCheckingAndSavings = function (oCustomer) { 8 | this.createAccount(oCustomer, true, true); 9 | }; 10 | BankAccount.prototype.createAccount = function (oCustomer, bWithChecking, bWithSavings) { 11 | // do work 12 | }; -------------------------------------------------------------------------------- /29 Remove Middle Man/problem/AccountDataProvider.js: -------------------------------------------------------------------------------- 1 | function AccountDataProvider() { 2 | 3 | } 4 | AccountDataProvider.prototype.getAccount = function (nId) { 5 | // get account 6 | }; -------------------------------------------------------------------------------- /29 Remove Middle Man/problem/AccountManager.js: -------------------------------------------------------------------------------- 1 | function AccountManager(oDataProvider) { 2 | this.oDataProvider = oDataProvider; 3 | } 4 | AccountManager.prototype.getAccount = function (nId) { 5 | return this.oDataProvider.getAccount(nId); 6 | }; 7 | -------------------------------------------------------------------------------- /29 Remove Middle Man/problem/Consumer.js: -------------------------------------------------------------------------------- 1 | function Consumer(oAccountManager) { 2 | this.oAccountManager = oAccountManager; 3 | } 4 | Consumer.prototype.get = function (nId) { 5 | var oAccount = this.oAccountManager.getAccount(nId); 6 | }; -------------------------------------------------------------------------------- /29 Remove Middle Man/solution/AccountDataProvider.js: -------------------------------------------------------------------------------- 1 | function AccountDataProvider() { 2 | 3 | } 4 | AccountDataProvider.prototype.getAccount = function (nId) { 5 | // get account 6 | }; -------------------------------------------------------------------------------- /29 Remove Middle Man/solution/Consumer.js: -------------------------------------------------------------------------------- 1 | function Consumer(oDataProvider) { 2 | this.oDataProvider = oDataProvider; 3 | } 4 | Consumer.prototype.get = function (nId) { 5 | var oAccount = this.oDataProvider.getAccount(nId); 6 | } -------------------------------------------------------------------------------- /30 Return ASAP/problem/Order.js: -------------------------------------------------------------------------------- 1 | function Order() { 2 | this.oCustomer = null; 3 | } 4 | Order.prototype.calculateOrder = function (oCustomer, aProducts, nDiscounts) { 5 | var nOrderTotal = 0; 6 | this.oCustomer = oCustomer; 7 | if (aProducts.length > 0) { 8 | nOrderTotal = aProducts.sum('nPrice'); 9 | if (nDiscounts > 0) { 10 | nOrderTotal -= nDiscounts; 11 | } 12 | } 13 | return nOrderTotal; 14 | }; -------------------------------------------------------------------------------- /30 Return ASAP/solution/Order.js: -------------------------------------------------------------------------------- 1 | function Order() { 2 | this.oCustomer = null; 3 | } 4 | Order.prototype.calculateOrder = function (oCustomer, aProducts, nDiscounts) { 5 | var nOrderTotal; 6 | if (aProducts.length === 0) { 7 | return 0; 8 | } 9 | this.oCustomer = oCustomer; 10 | nOrderTotal = aProducts.sum('nPrice'); 11 | if (nDiscounts === 0) { 12 | return nOrderTotal; 13 | } 14 | nOrderTotal -= nDiscounts; 15 | return nOrderTotal; 16 | }; -------------------------------------------------------------------------------- /31 Replace conditional with Polymorphism/problem/Customer.js: -------------------------------------------------------------------------------- 1 | function Customer() { 2 | 3 | } -------------------------------------------------------------------------------- /31 Replace conditional with Polymorphism/problem/Employee.js: -------------------------------------------------------------------------------- 1 | function Employee() { 2 | Customer.call(this); 3 | } 4 | Employee.prototype = new Customer(); -------------------------------------------------------------------------------- /31 Replace conditional with Polymorphism/problem/NonEmployee.js: -------------------------------------------------------------------------------- 1 | function NonEmployee() { 2 | Customer.call(this); 3 | } 4 | NonEmployee.prototype = new Customer(); -------------------------------------------------------------------------------- /31 Replace conditional with Polymorphism/problem/OrderProcessor.js: -------------------------------------------------------------------------------- 1 | function OrderProcessor() { 2 | 3 | } 4 | OrderProcessor.prototype.processOrder = function (oCustomer, aProducts) { 5 | var nOrderTotal = aProducts.sum('nPrice'); 6 | 7 | if (oCustomer instanceof Employee) { 8 | nOrderTotal -= nOrderTotal * 0.15; 9 | } 10 | else if (oCustomer instanceof NonEmployee) { 11 | nOrderTotal -= nOrderTotal * 0.05; 12 | } 13 | return nOrderTotal; 14 | }; -------------------------------------------------------------------------------- /31 Replace conditional with Polymorphism/solution/Customer.js: -------------------------------------------------------------------------------- 1 | function Customer() { 2 | this.nDiscountPercentage = 0; 3 | } -------------------------------------------------------------------------------- /31 Replace conditional with Polymorphism/solution/Employee.js: -------------------------------------------------------------------------------- 1 | function Employee() { 2 | Customer.call(this); 3 | this.nDiscountPercentage = 0.15; 4 | } 5 | Employee.prototype = new Customer(); -------------------------------------------------------------------------------- /31 Replace conditional with Polymorphism/solution/NonEmployee.js: -------------------------------------------------------------------------------- 1 | function NonEmployee() { 2 | Customer.call(this); 3 | this.nDiscountPercentage = 0.05; 4 | } 5 | NonEmployee.prototype = new Customer(); -------------------------------------------------------------------------------- /31 Replace conditional with Polymorphism/solution/OrderProcessor.js: -------------------------------------------------------------------------------- 1 | function OrderProcessor() { 2 | 3 | } 4 | OrderProcessor.prototype.processOrder = function (oCustomer, aProducts) { 5 | var nOrderTotal = aProducts.sum('nPrice'); 6 | nOrderTotal -= nOrderTotal * oCustomer.nDiscountPercentage; 7 | return nOrderTotal; 8 | }; -------------------------------------------------------------------------------- /Array_Sum.js: -------------------------------------------------------------------------------- 1 | if (!Array.prototype.sum) { 2 | Array.prototype.sum = function (sProperty) { 3 | var aItems = this.concat(), 4 | oItem = aItems.shift(), 5 | nValue, 6 | nItemValue, 7 | nSum = 0; 8 | while (oItem) { 9 | nItemValue = oItem; 10 | if (sProperty) { 11 | nItemValue = oItem[sProperty]; 12 | } 13 | nValue = parseInt(nItemValue, 10); 14 | if (!isNaN(nValue)) { 15 | nSum += nValue; 16 | } 17 | oItem = aItems.shift(); 18 | } 19 | return nSum; 20 | }; 21 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Here you can find the book that inspired me: 2 | 3 | [31 days of Refactoring](http://lostechies.com/wp-content/uploads/2011/03/31DaysRefactoring.pdf) --------------------------------------------------------------------------------