The Artima Developer Community
Sponsored Link

.NET Buzz Forum
Refactoring complex classes using Composition Part 1

0 replies on 1 page.

Welcome Guest
  Sign In

Go back to the topic listing  Back to Topic List Click to reply to this topic  Reply to this Topic Click to search messages in this forum  Search Forum Click for a threaded view of the topic  Threaded View   
Previous Topic   Next Topic
Flat View: This topic has 0 replies on 1 page
Jonathan Crossland

Posts: 630
Nickname: jonathanc
Registered: Feb, 2004

Jonathan Crossland is a software architect for Lucid Ocean Ltd
Refactoring complex classes using Composition Part 1 Posted: Apr 8, 2009 7:06 AM
Reply to this message Reply

This post originated from an RSS feed registered with .NET Buzz by Jonathan Crossland.
Original Post: Refactoring complex classes using Composition Part 1
Feed Title: Jonathan Crossland Weblog
Feed URL: http://www.jonathancrossland.com/syndication.axd
Feed Description: Design, Frameworks, Patterns and Idioms
Latest .NET Buzz Posts
Latest .NET Buzz Posts by Jonathan Crossland
Latest Posts From Jonathan Crossland Weblog

Advertisement

Using Design Patterns which deal with compositional power, such as Wrapper, Facade, Adaptor, Bridge, Proxy and others are extremely useful for breaking large classes down. Rather have 10 smaller classes than 1 large one.

Well here is a very simple start to how to get your refactoring of that large class under way. Please be sure to compile your project after each step, to fix any errors, before moving to the next step.

Step 1

Split the class into two and create a wrapper.
  1. Pick a very large, complex class. Mine is called "Runtime"
  2. Refactor the name of the class. I will call mine "RuntimeExecutor". Add any suffix for the moment, you can always come back to it. (Naming classes becomes harder and harder as you divide classes.)
  3. Add a new class with the "old name". Runtime.
  4. Extract the Interface of ActionExecutor. In VS.NET you simply right-click on the RuntimeExecutor class, and select Refactor | Extract Interface
    For this exercise, simply select all the members.
  5. A new class file with IRuntimeExecutor interface is created.
  6. Now implement the interface on the Runtime class.
  7. And create an Instance of the RuntimeExecutor from within the constructor of Runtime

It will look something like the code below

//abbreviated version of the class.
    public class Runtime : IActionExecutor
    {
        RuntimeExecutor _Executor; // this is the original class, renamed and now included as variable

        public Runtime()
        {
            _Executor = new RuntimeExecutor(); // we create the instance
        }

        #region IRuntimeExecutor Members

        public void Start()
        {
            _Executor.Start(); //we call the executor
        }

        public void Stop()
        {
            _Executor.Stop(); //we call the executor
        }

        #endregion
    }


Step 2

In the code above, you can see that I have added _Executor.Start() to the Start method. So in effect, Runtime is simple wrapping the Start of RuntimeExecutor. Now the next few steps are harder, but will increase the rewards.
  1. Create a new class suffixed with State. I called mine RuntimeState
  2. Take all the fields and properties for those fields from RuntimeExecutor, and cut/paste into State.
  3. If you only have Fields, refactor them so that you now have Proeprties for those fields
  4. Add a private field for the RuntimeState in RuntimeExecutor and
  5. Modify the contructor of RuntimeExecutor by adding "RuntimeState state" as a new parameter, mapping the parameter to the field.


    //new state class
    internal class RuntimeState
    {
        private string _Field;
       
        public string Field
        {
            get { return _Field; }
            set { _Field = value; }
        }

    }

    internal class RuntimeExecutor : IRuntimeExecutor
    {
        
        private RuntimeState _State; //new field, replaces all the other fields that were here

        public RuntimeExecutor(RuntimeState state) //new param
        {
            _State = state; //set it and use it

            //now wherever it used the old fields, map it to the _State.NewField
           _State.Field = "some value";

        }
     }


So at this point, instead of 1 class, you have three. We refactored the class into two, the original and the State version. And we wrapped it higher up, by renaming it and substituting it for the new wrapper.
  1. RuntimeExecutor (renamed original)
  2. Runtime (new, a wrapper for RuntimeExecutor)
  3. RuntimeState, (new split all properties and fields from RuntimeExecutor)

Step 3

We now need to split the original class further. This time instead of wrapping it, or refactoring UP, we now need to refactor down. Inspect the original class, and locate any methods that can be isolated and split from the class with minimal fuss.
  1. Locate methods that are only looking at RuntimeState only, and move them, cut/paste into the RuntimeState class.
  2. Make these methods internal, and point RuntimeExecutor to _State.MethodName
  3. Locate methods that are utility functions to the class, such as getConfiguration, or IsRunning, and that can be moved to another class. If you have such functions, create a new class for it, and move it to the new location

So now you should have 4 classes from the original 1.
  1. RuntimeExecutor (renamed original)
  2. Runtime (new, a wrapper for RuntimeExecutor)
  3. RuntimeState (now contains state related functions)
  4. Utility class containing helpful functions



Conclusion

I follow this pattern for refactoring large classes that does not present itself clearly as refactorable. It gives me a set way of doing things, which then offers up more refactoring choices as I go along.
For example. When I find a lot of state, perhaps I refactor that too, into even smaller state classes.
Importantly though as you go along, you should be on the lookout for common classes. Perhaps another large classes State was extremely similar.
I then follow a pattern using inheritance for refactoring, and perhaps break things down even smaller.


In Part 2, I will show you how to utilize the wrapper for even more refactoring loveliness.

Read: Refactoring complex classes using Composition Part 1

Topic: Download the Free !exploitable Crash Analyzer Previous Topic   Next Topic Topic: Smegging Code Metrics

Sponsored Links



Google
  Web Artima.com   

Copyright © 1996-2019 Artima, Inc. All Rights Reserved. - Privacy Policy - Terms of Use