Software Reengineering Refactoring To Patterns

2y ago
12 Views
2 Downloads
784.01 KB
64 Pages
Last View : 13d ago
Last Download : 3m ago
Upload by : Sutton Moon
Transcription

Software ReengineeringRefactoring To PatternsMartin Pinzger & Andy ZaidmanDelft University of Technology

OutlineIntroductionDesign PatternsRefactoring to PatternsConclusions2

The Reengineering Life-Cycle(1) requirementanalysis(3) problemdetectionNewRequirements(4) problemresolutionDesigns(2) modelcaptureCode3

Object-Oriented Design Patterns„Descriptions of communicating objects and classesthat are customized to solve a general designproblem in a particular context.“![Gamma, Helm, Johnson, Vlissides 1995]4

Design Patterns IdeaReoccurring design problems ! idea:Do not solve the problem again. use an existing pattern that can be parameterizedfrom which concrete solutions can be derivedReuse design knowledgeVocabulary for communicating design5

Elements of Design PatternsPattern nameDesign VocabularyProblemWhen to apply the pattern?List of preconditionsSolutionAbstract description of a design problem and how a general arrangements ofclasses and objects solves itConsequencesImpact on flexibility, extensibility, portability, etc.6

Describing Design PatternsElements of the descriptionPattern name and classificationIntent, Also known as, MotivationApplicabilityStructure, Participants, CollaborationsConsequencesImplementationSample code, Known uses, Related patterns7

Design Patterns (GoF) ClassificationCreationalScopeClassFactory MethodPurposeStructuralAdapter (class)BehavioralInterpreterTemplate MethodObjectAbstract FactoryAdapter (object)Chain of lyweightObserverProxyStateStrategyVisitor8

Additional ReadingDesign Patterns: Elements of Reusable Object-Oriented SoftwareErich Gamma, Richard Helm, Ralph Johnson, John M. VlissidesOnline: http://sourcemaking.com/design patterns9

Refactoring to Patterns

Design Patterns and Refactorings“There is a natural relation between patterns and refactoring.Patterns are where you want to be; refactorings are ways toget there from somewhere else.”[Fowler 1999]11

Refactoring to Patterns: BookA set of composite refactorings torefactor towards design patternsJoshua Kerievsky, Addison-Wesley, 2005Some patterns px?p 139860712

Overview of RefactoringsCreationMove functionality to create instances of complex classes to Factory andBuilder classesSimplificationSimplify the source code by introducing strategy, state, commands, composites,and decoratorsGeneralizationTransform specific code into general-purpose code by introducing TemplateMethod, Composite, Observer, Adapter, and Interpreter13

Overview of Refactorings (cont.)ProtectionProtect existing code from modifications by introducing a Singleton and NullObjectAccumulationAccumulating information by introducing a Visitor14

Refactoring to Patterns: ExamplesFactory MethodIntroduce Polymorphic Creation with Factory MethodStateFactor out StateObserverReplace Hard-Coded Notifications with Observer15

Example 1: CreationIntroduce Polymorphic Creation withFactory Method

Example BuilderTestpublic class DOMBuilderTest extends TestCase {private OutputBuilder builder;public void testAddAboveRoot() {String invalidResult “ orders . /orders ”;builder new ”);try {builder.addAbove(“customer”);} catch (RuntimeException re) {fail(“Message”, re);}}}public class XMLBuilderTest extends TestCase {private OutputBuilder builder;public void testAddAboveRoot()// the samebuilder new XMLBuilder(“orders”);// the same}}17

Introduce Factory MethodProblemClasses in a hierarchy implement a method similarly, except for an objectcreation stepSolutionMake a single superclass version of the method that calls a Factory Method tohandle the instantiation18

Factory Method PatternIntentDefine an interface for creating an object, but let subclasses decide which classto instantiate.MotivationEncapsulate the knowledge of which subclass to create to a factory methodApplicabilityClass wants its subclasses to specify the objects it creates19

Factory Method Pattern: d()AnOperation()product FactoryMehod()ConcreteCreatorFactoryMethod()return new ConcreteProduct()20

Example BuilderTest: Class DiagramTestCaseDomBuilderTesttestAddAboveRoot(): void.builder new ot(): void.builder new ilder21

Introduce Factory Method: MechanicsExtract Method on creation codeRepeat in sibling subclassesExtract Superclass to create CreatorPull Up Method and Form Template Method of testAddAboveRoot()Add abstract Factory MethodImplement concrete factory method in subclasses22

Extract Method on creation codepublic class DOMBuilderTest extends TestCase {private OutputBuilder builder;private OutputBuilder createBuilder(String rootName) {return new DOMBuilder(“orders”);}public void testAddAboveRoot() {String invalidResult “ orders . /orders ”;builder der”);.}}public class XMLBuilderTest extends TestCase {private OutputBuilder builder;private OutputBuilder createBuilder(String rootName) {return new XMLBuilder(“orders”);}public void testAddAboveRoot().builder createBuilder(“orders”);.}}23

Extract Superclasspublic abstract class AbstractBuilderTest extends TestCase {}public class DOMBuilderTest extends AbstractBuilderTest {.}public class XMLBuilderTest extends AbstractBuilderTest {.}24

Form Template Method and Pull Up Fieldpublic abstract class AbstractBuilderTest extends TestCase {protected OutputBuilder builder;protected abstract OutputBuilder createdBuilder (String rootName);}25

Result Refactoring tbuilder : OutputBuildercreateBuilder(rootName:String) : OutputBuildertestAddAboveRoot() : void.builder TestcreateBuilder(rootName:String): OutputBuilderreturn new ootName:String): OutputBuilderreturn new XMLBuilder(rootName);26

Benefits and Liabilities Reduces duplication resulting from a custom object creation step Effectively communicates where creation occurs and how it maybe overridden Enforces what type a class must implement to be used by aFactory Method- May require you to pass unnecessary parameters to some FactoryMethod implementers27

Example 2: SimplicficationFactor out State

Example SystemPermissionpublic class SystemPermission.private SystemProfile profile;private SystemUser requestor;private SystemAdmin admin;private boolean isGranted;private String QUESTED "REQUESTED";CLAIMED "CLAIMED";GRANTED "GRANTED";DENIED "DENIED";public SystemPermission(SystemUser requestor, SystemProfile profile) {this.requestor requestor;this.profile profile;state REQUESTED;isGranted false;notifyAdminOfPermissionRequest();}.29

Example SystemPermission (cont.).public void claimedBy(SystemAdmin admin) {if (!state.equals(REQUESTED)) return;willBeHandledBy(admin);state CLAIMED;}public void deniedBy(SystemAdmin admin) {if (!state.equals(CLAIMED)) return;if (!this.admin.equals(admin)) return;isGranted false;state ic void grantedBy(SystemAdmin admin) {if (!state.equals(CLAIMED)) return;if (!this.admin.equals(admin)) return;state GRANTED;isGranted true;notifyUserOfPermissionRequestResult();}}30

Factor out StateProblemHow to make a class extensible whose behavior depends on a complexevaluation of its state?SolutionEliminate complex conditional code over an object’s state by applying theState Pattern31

State PatternIntentAllow an object to alter its behavior when its internal state changes. Theobject will appear to change its class.ApplicabilityAn object’s behavior depends on its state, and it must change its behavior atrun-time depending on that stateOperations have large, multipart conditional statements that depend on theobject’s state.32

State Pattern: ()ConcreteStateAHandle()ConcreteStateBHandle()33

Example SystemPermission: Class DiagramSystemPermissionstate : StringREQUESTES : StringCLAIMED : StringGRANTED : StringDENIED : String.claimedBy(.) : voidgrantedBy(.) : voiddeniedBy(.) : vodi.if (! state.equals(REQUESTED) return;willBeHandledBy(admin);state CLAIMED;34

Change: Adding two more states35

Replace Conditionals with State: MechanicsReplace Type Code with ClassOn the original state field in the context classExtract SubclassTo produce one subclass per constant (state) and declare state superclass asabstractMove MethodOn context class methods that change the value of original state variable36

Replace Type Code with State Classpublic class PermissionState {private String name;private PermissionState(String name) {this.name name;}public final static PermissionState REQUESTED new PermissionState("REQUESTED");public final static PermissionState CLAIMED new PermissionState("CLAIMED");public final static PermissionState GRANTED new PermissionState("GRANTED");public final static PermissionState DENIED new PermissionState("DENIED");public final static PermissionState UNIX REQUESTED new PermissionState("UNIX REQUESTED");public final static PermissionState UNIX CLAIMED new PermissionState("UNIX CLAIMED");public String toString() {return name;}}37

Replace Type Code with State Class (cont.)public class SystemPermission {private PermissionState permissionState;public SystemPermission(SystemUser requestor, SystemProfile profile) {.setState(PermissionState.REQUESTED);.}private void setState(PermissionState state) {permissionState state;}public void claimedBy(SystemAdmin admin) {if (!getState().equals(PermissionState.REQUESTED)&& !getState().equals(PermissionState.UNIX REQUESTED))return;.}.}38

Extract Subclass for each State (Constant)public abstract class PermissionState {private String name;private PermissionState(String name) {this.name name;}public final static PermissionState REQUESTED new PermissionRequested();.}public class PermissionRequested extends PermissionState {public PermissionRequested() {super(“REQUESTED”);}}public class PermissionClaimed extends PermissionState { . }public class PermissionDenied extends PermissionState { . }public class PermissionGranted extends PermissionState { . }public class UnixPermissionRequested extends PermissionState { . }public class UnixPermissionClaimed extends PermissionState { . }39

Move State Trans. Logic to State Classpublic abstract class PermissionState.public void claimedBy(SystemAdmin admin, SystemPermission permission) {if (!permission.getState().equals(REQUESTED) &&!permission.getState().equals(UNIX );if n.setState(CLAIMED);else if (permission.getState().equals(UNIX REQUESTED)) {permission.setState(UNIX CLAIMED);}}40

Move State Trans. Logic (cont.)public class SystemPemission {.void setState(PermissionState state) { // now has package-level visibilitypermissionState state;}public void claimedBy(SystemAdmin admin) {state.claimedBy(admin, this);}void willBeHandledBy(SystemAdmin admin) {this.admin admin;}}41

Move State Trans. Logic to Subclassespublic class PermissionRequested extends PermissionState {.public void claimedBy(SystemAdmin admin, SystemPermission permission) tate(CLAIMED);}}42

Move State-Transition to Subclasses (cont.)public class PermissionClaimed extends PermissionState.public void deniedBy(SystemAdmin admin, SystemPermission permission) {if ublic void grantedBy(SystemAdmin admin, SystemPermission permission) {if (!permission.getAdmin().equals(admin))return;if )&& !permission.isUnixPermissionGranted()) {permission.setState(UNIX PermissionRequestResult();}43

Move State-Transition to Subclasses (cont.)public abstract class PermissionState {public String toString();public void claimedBy(SystemAdmin admin, SystemPermission permission) {}public void deniedBy(SystemAdmin admin, SystemPermission permission) {}public void grantedBy(SystemAdmin admin, SystemPermission permission) {}}44

Result Refactoring mPermissionclaimedBy(.) : voidgrantedBy(.) : voiddeniedBy(.) : voidpermissionStatePermissionStatename : StringREQUESTES : PermissionStateCLAIMED : PermissionStateGRANTED : PermissionStateDENIED : PermissionState.PermissionState(name : String)claimedBy(.) : voidgrantedBy(.) : voiddeniedBy(.) : vodiPermissionClaimedgrantedBy(.) : voiddeniedBy(.) : voidPermissionRequestedclaimedBy(.) : ermission.setState(CLAIMED);45

Benefits and Liabilities Reduces or removes state-changing conditional logic Simplifies complex state-changing logic Provides a good bird’s-eye view of state-changing logic- Complicates design when state transition logic is already easy tofollow46

Example 3: GeneralizationReplace Hard-Coded Notifications with Observer

Example: TestResultpublic class UITestResult extends TestResult {private TestRunner runner;UITestResult(TestRunner runner) {this.runner runner;}public synchronized void addFailure(Test test, Throwable t) {super.addFailure(test, t);runner.addFailure(this, test, t); // notification of TestRunner}}public class TestRunner extends Frame {private TestResult testResult;protected TestResult createdTestResult() {return new UITestResult(this);}public synchronized void runSuite() {testResult ic void addFailure(TestResult result, Test test, Throwable t) {// display the test result}}48

Replace Notifications with ObserverProblemSubclasses are hard-coded to notify a single instance of another classSolutionRemove the subclass by making their superclass capable of notifying one ormore instances of any class that implements an observer interface49

Observer PatternIntendMaintain a dependency between a central object (Subject) and multipledependent objects (Observers)MotivationDecouple a subject from its observersApplicabilityWhen an instance must notify more than one receiver instance,E.g., when there are various views (Observers) on the same model instance(Subject)50

Observer Pattern: Structurefor (Observer o : observers) {o.update();}Subjectattach(observer:Observer) : voiddetach(observer:Observer) : voidnotify() : voidConcreteSubjectstate : StategetState() : StateobserverssubjectObserverupdate() : voidConcreteObserverobserverState : Stateupdate() : voidobserverState subject.getState();51

Example TestResult: Class esultsHard-Coded Notificationstextui.TestRunnerui.TestRunner52

Repl. Notific. with Observer: MechanicsMove custom behavior to receiverExtract Interface on a receiver to produce an observer interfaceOnly methods called by its notifierMake every receiver implement the observer interfacePull Up Method on notification methods in notifier classesUpdate notification implementationAdd collection to subject and update observer to register andcommunicate with the subject53

Move Custom Behavior to Receiverpackage textui;public class TextTestResult extends TestResult {private TestRunner runner;TextTestResult(TestRunner runner) {this.runner runner;}public synchronized void addError(Test test, Throwable t) {super.addError(test, t);runner.addError(this, test, t);}}package textui;public class TestRunner .protected TextTestResult createdTestResult() {return new TextTestResult(this);}public void addError(TestResult result, Test test, Throwable t) {System.out.println(“E”);}}54

Extract Observer Interfacepublic class TextTestResult extends TestResult .public synchronized void addError(Test test, Throwable t) {super.addError(test, t);runner.addError(this, test, t);}public synchronized void addFailure(Test test, Throwable t) {super.addFailure(test, t);runner.addFailure(this, test, t);}public synchronized void startTest(Test test) {super.startTest(test);runner.startTest(this, test);}}public interface TestListener {public void addError(TestResult testResult, Test test, Throwable t);public void addFailure(TestResult testResult, Test test, Throwable t);public void startTest(TetResult testResult, Test test);public void endTest(TestResult testResult, Test test);}public class TestRunner implements TestListener .public void endTest(TestResult testResult, Test test) { }}55

Make Receiver Implement the Interfacepackage ui;public class TestRunner extends Frame implements TestListener {.}package ui;public class UITestResult extends TestResult .protected TestListener runner;UITestResult(TestListener runner) {this.runner runner;}}package textui;public class TextTestResult extends TestResult .protected TestListener runner;TextTestResult(TestListener runner) {this.runner runner;}}56

Pull Up Methods in Observerspublic class TestResult .protected TestListener runner;public TestResult() {failures new ArrayList TestFailure ();errors new ArrayList TestError ();runTests 0;stop false;}public TestResult(TestListener runner) {this();this.runner runner;}public synchronized void addError(Test test, Throwable t) {errors.add(new TestError(test, t));runner.addError(this, test, t);}.}package ui;public class UITestResult extends TestResult { }package textui;public class TextTestResult extends TestResult { }57

Update Observers to Work with Subjectpackage textui;public class TestRunner implements TestListener .protected TestResult createTestResult() {return new TestResult(this);}}package ui;public class TestRunner implements TestListener .protected TestResult createTestResult() {return new TestResult(this);}public synchronized void runSuite() {.TestResult result createTestResult();testSuite.run(testResult);}58

Update Subject to Notify many Observerspublic class TestResult .protected List TestListener observers new ArrayList TestListener ();public void addObserver(TestListener observer) {observers.add(observer);}public synchronized void addError(Test test, Throwable t) {errors.add(new TestError(test, t));for (TestListener observer : observers) {observer.addError(this, test, t);}}.}59

Update Observer to Register with Subjectpackage textui;public class TestRunner implements TestListener .protected TestResult createTestResult() {TestResult testResult new rn testResult;}}60

Result: Refactoring i.TestRunner61

Benefits and Liabilities Loosely couples a subject with its observers Supports one or many observers- Complicate designWhen a hard-coded notification will sufficeWhen you have cascading notifications- May cause memory leaks when observers aren’t removed fromtheir subjects62

More Refactorings To PatternsA set of composite refactorings torefactor towards design patternsJoshua Kerievsky, Addison-Wesley, 2005Some patterns px?p 139860763

ConclusionsRefactoring to PatternsKnown and tested solutions for similar design problemsEncapsulates and simplifies logicIncreases extensibility (interfaces, loose coupling)But, don’t overdo itOnly use a pattern when it (really) makes sense64

Refactoring To Patterns Martin Pinzger & Andy Zaidman Delft University of Technology. 2 Outline Introduction Design Patterns Refactoring to Patterns . Refactoring to Patterns: Book 12 Joshua Kerievsky, Addison-Wesley, 2005 A set of composite refactorings to

Related Documents:

Refactoring to Patterns Argue that design patterns can remove code smells More high level Each refactoring to patterns is composed of a set of Primitive refactorings Don’t Forget Testing after refactoring! 21 refactorings are introduced in: – Refactoring to Patterns by Joshua Kerievsky , Addison-Wesley 2004. 30

Moreover, Joshua Kerievsky had another point of view for the refactoring issue. He also worked on code smell-refactoring subject; however, he added a third dimension to the subject, which is design patterns. In his book, Refactoring to Patterns, it is stated that: ”Each pattern is a three part rule, which expresses a relation

the input of dynamic analysis without manual checking by developers. In this paper, we propose a novel automated test code refactoring system dedicated to dynamic analysis, called B-Refactoring,1 detects and splits impure test cases. In our work, an impure test case is a test case, which executes an unproc

Refactoring to Patterns by Joshua Kerievsky Expands the subject a lot Contains lots of smaller samples Requires reading a few times. But each sample is already prepared to refactoring towards given design pattern This is rarely the case in legacy code 11

Martin Fowler et al., Refactoring: Improving the Design of Existing Code, Addison-Wesley, 1999 (introductory) Fundamental introduction to refactoring. Joshua Kerievsky, Refactoring to Patterns, Addison-Wesley, 2004 (intermediate) Guide to improving the design of existing code with pattern-directed refactorings.

Refactoring to Patterns by Joshua Kerievsky Addison-Wesley Longman , 2044. 1. Make sure your tests pass (You need to ensure that the code behaves the same after refactoring) 2. Find the bad code 3. Find a solution how to make it look nice 4. Modify the code

mation script from a change example and applies it to a user-selected target. We showed that Sydit . Real-World Refactoring It is widely believed that refactoring improves software quality and pro-ductivity. To create a scientific foundation that can help engineers to make data-driven refactoring .

PASSOVER BLUEBERRY MUFFINS (Alexa & Riley Newbold) Ingredients: -1/3 cup butter -1 scant cup of sugar -3 eggs -1/2 teaspoon vanilla -1/2 cup matzo cake meal -1/4 cup potato starch -1/4 teaspoon salt -1 cup blueberries (frozen, drained)— don’t defrost -Cinnamon sugar . Directions: Cream sugar and butter. Add three eggs one at a time, beating after each. Add vanilla and mix. Add matzo cake .