views:

299

answers:

5

I am just embarking on my first large-scale refactor, and need to split an (unfortunately large) class into two, which then communicate only via an interface. (My Presenter has turned out to be a Controller, and needs to split GUI logic from App logic). Using C# in VisualStudio 2008 and Resharper, what is the easiest way to achieve this?

What I am going to try is a) Collect the members for the new class and "extract new class" b) clean up the resulting mess c) "Extract Interface" d) chase down any references to the class and convert them to interface references

but I have never done this before, and wonder whether anyone knows any good tips or gotchas before I start ripping everything apart... Thanks!

+2  A: 

Baby steps.

Step 1: Make a small change using Resharper's excellent Refactoring.
Step 2: Test (preferably unit test) to ensure the code still works
Step 3: Commit to source control

Repeat these 3 steps many times.

Maybe this won't work if you are doing one of the those "must be a big step all at once" refactorings. In which case, do as many small refactorings as possible before taking the plunge into the big step.

Steve McLeod
+5  A: 

Call me old-fashion, but personally, I use the automated functions you described only when it's for technical tasks (such as renaming, etc...)

For all other refactoring, like extracting interfaces and such, I prefer to do manually. You will find out that there is even more refactoring you can do and usually the code will come out cleaner.

Yuval A
Unless you use JetBrains's excellent tools!
Steve McLeod
A: 

Short answer here first, I'm going to write blog post about it, thanks for an idea!

So, let's assume we have this:

class PresenterAndController
  {
    public void Control()
    {
      Present();
    }

    public void Present()
    {
      // present something
    }
  }

First we need to convert all direct members usages into indirect, i.e. qualify them with field. To do this, use extract superclass refactoring to extract Presenter portion into superclass:

  internal class Presenter
  {
    public void Present()
    {
      // present something
    }
  }

  class PresenterAndController : Presenter
  {
    public void Control()
    {
      Present();
    }
  }

Create field in PresenterAndController which will be delegating one and use Generate (Alt-Ins) to create delegating members. They will happen to hide base methods, since they are the same:

  internal class Presenter
  {
    public void Present()
    {
      // present something
    }
  }

  class PresenterAndController : Presenter
  {
    private Presenter myPresenter;

    public void Present() // hides base method
    {
      myPresenter.Present();
    }

    public void Control()
    {
      Present(); // it now references method from this type
    }
  }

Remove Presenter from the inheritance list and you are done with splitting classes. Now you can extract interfaces, use base types where possible and otherwise tidy it up.

Ilya Ryzhenkov
A: 

I've never used VisualStudio, but I find the automatic refactoring in Eclipse to be pretty reliable - at least as reliable as I would be doing the same job.

DJClayworth
+1  A: 

I only have one important piece of advice - make absolutely sure you can revert back to the state before you started the refactor without losing anything. Then just dive in and go for it. You may well end up having to stop and start again, but that's nothing to be afraid of (as long as you heeded my one piece of advice). You'll learn a lot doing it.

DJClayworth