A refactoring example

To show you how these principles work in action, we'll walk you through a refactoring example. Figure 5.1 shows a window that might be used as the front end to a Microsoft Access-like database.

This layout is a little more complex than those we have seen so far, but by the standard of real-world applications, it is still quite simple. Listing 5.1 shows a poorly structured way to produce Figure 5.1. When people talk about UI

code being a mess, this is what they mean. Having several problems compressed into a few lines of code may be a bit of an exaggeration, but it's representative of

Figure 5.1 The sample window for the refactoring example the trouble you can get into in layout code. Certainly, it's representative of the trouble I get into when writing layout code.

Listing 5.1 An un-refactored way to produce figure 5.1

#!/usr/bin/env python import wx class RefactorExample(wx.Frame):

wx.Frame._init_(self, parent, id, 'Refactor Example', size=(34 0, 200)) panel = wx.Panel(self, -1) panel.SetBackgroundColour("White")

prevButton = wx.Button(panel, -1, "<< PREV", pos=(80, 0)) self.Bind(wx.EVT_BUTTON, self.OnPrev, prevButton) nextButton = wx.Button(panel, -1, "NEXT >>", pos=(16 0, 0)) self.Bind(wx.EVT_BUTTON, self.OnNext, nextButton) self.Bind(wx.EVT_CLOSE, self.OnCloseWindow)

openMenuItem = menu1.Append(-1, "&Open", "Copy in status bar") self.Bind(wx.EVT_MENU, self.OnOpen, openMenuItem) quitMenuItem = menu1.Append(-1, "&Quit", "Quit") self.Bind(wx.EVT_MENU, self.OnCloseWindow, quitMenuItem) menuBar.Append(menu1, "&File") menu2 = wx.Menu()

copyItem = menu2.Append(-1, "&Copy", "Copy") self.Bind(wx.EVT_MENU, self.OnCopy, copyItem) cutItem = menu2.Append(-1, "C&ut", "Cut") self.Bind(wx.EVT_MENU, self.OnCut, cutItem) pasteItem = menu2.Append(-1, "Paste", "Paste") self.Bind(wx.EVT_MENU, self.OnPaste, pasteItem) menuBar.Append(menu2, "&Edit") self.SetMenuBar(menuBar)

static = wx.StaticText(panel, wx.NewId(), "First Name", pos=(10, 50)) static.SetBackgroundColour("White")

text = wx.TextCtrl(panel, wx.NewId(), "", size=(100, -1), pos=(8 0, 50))

static2 = wx.StaticText(panel, wx.NewId(), "Last Name", pos=(10, 80)) static2.SetBackgroundColour("White")

text2 = wx.TextCtrl(panel, wx.NewId(), "", size=(100, -1), pos=(8 0, 80))

firstButton = wx.Button(panel, -1, "FIRST") self.Bind(wx.EVT_BUTTON, self.OnFirst, firstButton)

menu2.AppendSeparator()

optltem = menu2.Append(-1, "&Options...", "Display Options") self.Bind(wx.EVT_MENU, self.OnOptions, optltem)

lastButton = wx.Button(panel, -1, "LAST", pos=(240, 0)) self.Bind(wx.EVT_BUTTON, self.OnLast, lastButton)

# Just grouping the empty event handlers together

def

OnPrev(self, event):

pass

def

OnNext(self, event):

pass

def

OnLast(self, event):

pass

def

OnFirst(self, event)

: pass

def

OnOpen(self, event):

pass

def

OnCopy(self, event):

pass

def

OnCut(self, event):

pass

def

OnPaste(self, event)

: pass

def

OnOptions(self, event): pass

def

OnCloseWindow(self,

event):

self.Destroy()

name == ' main ':

app = wx.PySimpleApp()

frame = RefactorExample(parent=None, id=-1)

frame.Show()

app.MainLoop()

app = wx.PySimpleApp()

frame = RefactorExample(parent=None, id=-1)

frame.Show()

app.MainLoop()

Let's categorize how this code example works against the principles in table 5.1. On the positive side, there's no deep nesting. On the negative side, the other three ideas listed in table 5.1 aren't followed at all. Table 5.2 summarizes the ways in which refactoring might improve this code.

Table 5.2 Refactoring opportunities in listing 5.1

Principle

Problem in code

No duplication

Several patterns are duplicated repeatedly, including "add a button, and give it an action," "add a menu item and give it an action," and "create a caption/text entry pair."

One thing at a time

This code does several things. In addition to basic frame setup, it creates the menu bar, adds the buttons, and adds the text fields. Worse, the three functions are mixed up through the code, as if late changes were just added at the bottom of the method.

Avoid magic literals

Every button, menu item, and text box has a literal string and a literal point in the constructor.

To give you a general idea of how to fix this code, we'll pull all the button code into a separate method.

Was this article helpful?

0 0

Post a comment