The Artima Developer Community
Sponsored Link

.NET Buzz Forum
Refactoring complex classes using Composition Part 2

0 replies.

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 flat view of this topic  Flat View
Previous Topic   Next Topic
Threaded 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 2 Posted: Apr 9, 2009 5: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 2
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


From Part 1, I showed you how I initially split a large class into a few more, splitting the complexity of having the code in one place. However, you will still find that for a really complex class, there will still be quite a lot to do. Here are a few more composition based things to consider for continuing the refactoring process.

Extract surrounding Exceptions

You will have to decide where you do this carefully, according to your own code, but I try to pull out the larger surrounding Try/Catch blocks into the wrapper, like Start method below. I now can remove the code from RuntimeExecutor for exceptions on as many methods as possible.

There may well be places you do not want to do this, but if your RuntimeExecutor class is private and only used by this wrapper, you should be able to remove most Exception handling in the wrapped class.
However, if the class is complex in this area, you may need an Exception Handling strategy instead. If your wrapped class, throws a complex amount of Exceptions in weird and wonderful areas within the code, you will have to think about it harder, but for most classes you can get away with extracting it.

//abbreviated version of the class.
    public class Runtime : IActionExecutor
    {
        public void Start()
        {
            try
            {
                _Executor.Start();
            }
            catch (Exception ex)
            {
                LastException = new RuntimeException("Execute Failed. See inner exception for details.", ex);
                Status = RuntimeStatus.Errored;
            }
        }

        public RuntimeException LastException
        {
            get
            {
                return _Exception;
            }
            protected set
            {
                _Exception = value;
            }
        }
    }


Splitting by lifespan and age

Think of your class in three main stages, Constructing, Running, Deconstructing and refactor based on it. For example, move Initialization code from RuntimeExecutor to Runtime. My class has an Initialize method and some code in its constructor. I now refactor this into the wrapper Runtime. I also move initilization checks to the wrapper.

    //abbreviated version of the class.
    public class Runtime : IActionExecutor
    {
        public void Start()
        {
            try
            {
                if (_IsInitialized)
                    _Executor.Start();
            }
            catch (Exception ex)
            {
                LastException = new RuntimeException("Execute Failed. See inner exception for details.", ex);
                Status = RuntimeStatus.Errored;
            }
        }

        private void Initialize()
        {
            try
            {
                //Initialization code, sets RuntimeState (see Part 1)
                _IsInitialized = true;
            }
            catch (Exception ex)
            {
                LastException = new RuntimeException("Execute Failed. See inner exception for details.", ex);
                Status = RuntimeStatus.Errored;
            }
        }
      
    }

I then do the same with any deconstruction code, so that they too exist in the Runtime class, and extracted from the RuntimeExecutor

Conclusion

The Utility class we created to move those more stateless methods into, can be expanded a little more, by moving even more methods from the main class into it. If you need to, you can even pass the RuntimeState instance via the constructor through to the class, so it can now have state. This will allow you to move even more methods into the Utility class. Remember this class is private and owned by the RuntimeExecutor. If some of these methods are more generic than that, you need to move it out into other classes.

We created four classes from one bulky one. Here is an example in code, of what we did.

 /// 
    /// We refactored UP, and created a Wrapper
    /// We moved wrapper methods, exceptions to this class
    /// 
    public class MyTypeWrapper
    {
        MyType _MyType;
        MyTypeState _MyState;

        public MyTypeWrapper()
        {
            _MyState = new MyTypeState();
            _MyType = new MyType(_MyState);
        }
    }

    /// 
    /// This is the original Bulky Class
    /// Some of its members moved UP (Wrapper)
    /// 
    internal class MyType
    {
        MyTypeState _MyState; //all fields now wrapped in MyTypeState
        MyTypeUtility _MyUtility;

        public MyType(MyTypeState myState)
        {
            _MyState = myState;
            _MyUtility = new MyTypeUtility();

        }
    }

    /// 
    /// All the fields moved from MyType to here
    /// 
    internal class MyTypeState
    {
        public MyTypeState()
        {
        }
    }

    /// 
    /// Methods moved here are stateless
    /// and/or if you add MyState, it can also be stateful.
    /// 
    internal class MyTypeUtility
    {
        public MyTypeUtility()
        {
        }
    }


Cleaning up

You now need to make sure that all is tidy. I usually do a mixture of the following.
  1. Rename methods to suit the new classes
  2. Split large methods at least into two
  3. Rename classes, to make sure they make sense
  4. Make RuntimeState, RuntimeExecutor classes private and check every method is private if its not called outside of its surroundings. If it is, I attempt to move the method to the utility class.
  5. See if the Interface we made in Part 1, is still required (most of the time it wont be, only useful for refactoring)
  6. If there are still large classes, I attempt it all from the start (Part 1)


Read: Refactoring complex classes using Composition Part 2


Topic: Refactoring complex classes using Composition Part 1 Previous Topic   Next Topic Topic: Download the Free !exploitable Crash Analyzer

Sponsored Links



Google
  Web Artima.com   

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