你会如何重构它以使其更好?

时间:2009-03-17 17:56:22

标签: c# asp.net refactoring

你会如何重构这样的东西?

protected void btnAdd_Click(object sender, EventArgs e)
{
    try
    {
        string username = txtUsername.Text.Trim().ToLower();
        string password = txtPassword.Text.Trim().ToLower();
        string email = txtEmail.Text.Trim().ToLower();
        string status = ddlStatus.SelectedValue.Trim();

        IUser user = UserFactory.getInstance().createUser(username, password, email,status);

        if (user.save())
        {
            jsMsgBox("Successfully added new user");
            Response.Redirect(ConfigurationManager.AppSettings["AdminLink"], true);
        }
        else
        {
            jsMsgBox("An error was encountered while trying to add a new user.");
        }
    }
    catch (Exception ex)
    {
        jsMsgBox("An Error was encountered while trying to add a new user.");
        lblInfo.Text = ex.Message;
        lblInfo.Visible = true;
    }
}

protected void btnUpdate_Click(object sender, EventArgs e)
{
    try
    {
        string username = txtUsername.Text.Trim().ToLower();
        string password = txtPassword.Text.Trim().ToLower();
        string email = txtEmail.Text.Trim().ToLower();
        int userPK = Int32.Parse(txtUserPK.Text.ToString());
        string status = ddlStatus.SelectedValue.Trim();

        IUser user = UserFactory.getInstance().createUser(userPK, username, password, email,status);

        if (user.save())
        {
            jsMsgBox("Successfully updated selected users information.");
            Response.Redirect(ConfigurationManager.AppSettings["AdminLink"], true);
        }
        else
        {
            jsMsgBox("An error was encountered while trying to update the selected users information.");
        }
    }
    catch (Exception ex)
    {
        jsMsgBox("An Error was encountered while trying to update the selected users information.");
        lblInfo.Text = ex.Message;
        lblInfo.Visible = true;
    }
}

小心

8 个答案:

答案 0 :(得分:3)

首先:

protected string cleaned(string raw) {
    raw.Text.Trim().ToLower()
    }
protected void attempt_to_save(IUser user, string task) {
    if (user.save()) {
        jsMsgBox("Successfully finished "+task);
        Response.Redirect(ConfigurationManager.AppSettings["AdminLink"], true);
      } else {
        jsMsgBox("An error was encountered while "+task);
        }
    }

protected void btnAdd_Click(object sender, EventArgs e)
{
    try
    {
        IUser user = UserFactory.getInstance().createUser(
            cleaned(txtUsername), 
            cleaned(txtPassword), 
            cleaned(txtEmail),
            ddlStatus.SelectedValue.Trim()
            );

        attempt_to_save(user,"adding a new user.");
    }
    catch (Exception ex)
    {
        jsMsgBox("An Error was encountered while trying to add a new user.");
        lblInfo.Text = ex.Message;
        lblInfo.Visible = true;
    }
}

protected void btnUpdate_Click(object sender, EventArgs e)
{
    try
    {

        IUser user = UserFactory.getInstance().createUser(
            Int32.Parse(txtUserPK.Text.ToString()), 
            cleaned(txtUsername), 
            cleaned(txtPassword), 
            cleaned(txtEmail),
            ddlStatus.SelectedValue.Trim()
            );

        attempt_to_save(user,"updating the selected users information.");
        }
    }
    catch (Exception ex)
    {
        jsMsgBox("An Error was encountered while trying to update the selected users information.");
        lblInfo.Text = ex.Message;
        lblInfo.Visible = true;
    }
}

请注意,有必要稍微改写一些消息。

答案 1 :(得分:3)

试试这个

首先创建一个用户信息对象

 class UserInfo
{
    public string username {get;set;}
    public string password {get;set;}
    public string email {get;set;}
    public string status {get;set;}
}

然后像这样重构您的代码

protected void btnAdd_Click(object sender, EventArgs e)
{
    UserInfo myUser = GetUserInfo();
    try
    {
        IUser user = UserFactory.getInstance().createUser(myUser);

        if (user.save())
        {
            jsMsgBox("Successfully added new user");
            Response.Redirect(ConfigurationManager.AppSettings["AdminLink"], true);
        }
        else
        {
            jsMsgBox("An error was encountered while trying to add a new user.");
        }
    }
    catch (Exception ex)
    {
        jsMsgBox("An Error was encountered while trying to add a new user.");
        lblInfo.Text = ex.Message;
        lblInfo.Visible = true;
    }
}

protected void btnUpdate_Click(object sender, EventArgs e)
{
    UserInfo myUser = GetUserInfo();
    int userPK = Int32.Parse(txtUserPK.Text.ToString());

    try
    {       
        IUser user = UserFactory.getInstance().createUser(userPK,myUser);

        if (user.save())
        {
            jsMsgBox("Successfully updated selected users information.");
            Response.Redirect(ConfigurationManager.AppSettings["AdminLink"], true);
        }
        else
        {
            jsMsgBox("An error was encountered while trying to update the selected users information.");
        }
    }
    catch (Exception ex)
    {
        jsMsgBox("An Error was encountered while trying to update the selected users information.");
        lblInfo.Text = ex.Message;
        lblInfo.Visible = true;
    }
}

private UserInfo GetUserInfo()
{
    UserInfo myUser = new UserInfo();

    UserInfo.username = txtUsername.Text.Trim().ToLower();
    UserInfo.password = txtPassword.Text.Trim().ToLower();
    UserInfo.email = txtEmail.Text.Trim().ToLower();
    UserInfo.status = ddlStatus.SelectedValue.Trim();

    return myUser;
}

答案 2 :(得分:2)

当两种方法相似时,我通常会采用两种方法。

在任何一种情况下,我通常会将它们更改为单个方法,并将彼此相似的行放在一起。

一个是拥有一个知道你所处方法的变量,并用它来确定要做什么。

如果(更新)    //使用更新行 其他   //使用添加行

您还必须能够处理可能无法在一种状态下初始化变量的情况(例如更新设置userPK,但添加不使用它)

这是一个快速简便的重构器,可以轻松组合2种方法,如果您的代码相当干净,很难搞乱。

另一种方式更复杂,用于将这种“组合”方法变成可重用的东西。我经常先做前一个,然后在必要时再继续......

有两种方法可以让您的组合课程更具可重用性。一个是“传入”差异。传入实现不同代码行的对象。

第二个是使它成为“父”类,并在你孩子的方法中实现不同的行。因此,当父级点击它必须进行创建时,它只会调用create()方法。将在子类中重写create()方法以运行一个方法或另一个方法。您可能会为每个代码差异委托这样的方法。

哦,如果只有“数据”不同,请说你的“组合”方法如下:

if(user==0)
    System.out.println("Bill was here");
else if(user==1)
    System.out.println("Bob was here");

我通常通过创建一个索引数组或枚举来解决这个问题,以便最终看起来像这样:

System.out.println(users[user]+" was here");

我知道这看起来很明显,但提取数据对于重构来说是一个巨大的帮助,如果你不知道接下来要做什么,这将是一个很好的开始......

答案 3 :(得分:2)

首先,摆脱这些try / catch,让asp.net配置友好的错误页面并记录任何未处理的异常。

在处理程序上,您希望他们非常清楚地了解正在发生的事情。我发现这个版本非常清楚这个版本:

protected void btnAdd_Click(object sender, EventArgs e)
{
    bool isInsert = true;
    bool saved = SaveUserFromControlInfo(isInsert);
    ShowJsMessageBox(
        saved, 
        "Successfully added new user", 
        "An error was encountered while trying to add a new user."
        );
    if(saved) RedirectToAdmin();
}
protected void btnUpdate_Click(object sender, EventArgs e)
{
    bool isInsert = false;
    bool saved = SaveUserFromControlInfo(isInsert);
    ShowJsMessageBox(
        saved,
        "Successfully updated selected users information.",
        "An error was encountered while trying to update the selected users information."
        );
    if (saved) RedirectToAdmin();
}

支持方法是:

void RedirectToAdmin()
{
    Response.Redirect(ConfigurationManager.AppSettings["AdminLink"], true);
}
void ShowJsMessageBox(bool success, string succesMessage, string failedMessage)
{
    jsMsgBox(success ? succesMessage : failedMessage);
}
void SaveUserFromControlInfo(bool isInsert)
{
    string username = txtUsername.Text.Trim().ToLower();
    string password = txtPassword.Text.Trim().ToLower();
    string email = txtEmail.Text.Trim().ToLower();
    string status = ddlStatus.SelectedValue.Trim();
    var userFactory = UserFactory.getInstance();
    IUser user;
    if( isInsert )
        user = userFactory.createUser(username, password, email, status);
    else
    {
        int userPK = Int32.Parse(txtUserPK.Text);
        user = userFactory.createUser(userPK, username, password, email, status);
    }
    return user.save();
}

我会稍微改变SaveUserFromControlInfo。我希望有一个与CreateUser请求相关联的类,它包含一个可选的userPK。

聚苯乙烯。我通常不这样做,因为我使用MVP,这个视图只有代码来获取控件中的用户信息(在其他地方定义了一个类)并将事件转发给演示者。

答案 4 :(得分:2)

我将在这里发表意见并建议这段代码并不特别需要重构。可能有空间使它更优雅,更简洁,或更强大,但因为它代表了死的简单和易于阅读。在这种情况下,我的直觉反应是,“如果它没有破裂,就不要修复它。”

编辑:所有说过的话,我至少推翻了其他三个答案。那里有一些很棒的想法。

编辑#2:看了之后,对我来说最明显的问题是重复以下代码:

    string username = txtUsername.Text.Trim().ToLower();
    string password = txtPassword.Text.Trim().ToLower();
    string email = txtEmail.Text.Trim().ToLower();
    string status = ddlStatus.SelectedValue.Trim();

这里真正的问题是,如果UI更改为添加,删除或重命名其中一个字段,则需要在两个位置更改此支持代码。如同其他几个答案所暗示的那样,在支持班级中发生这种情况要好得多。

答案 5 :(得分:1)

protected void btnAdd_Click(object sender, EventArgs e) { SaveUser();}
protected void btnUpdate_Click(object sender, EventArgs e) { SaveUser();}
private void SaveUser()
{
      int? userId = string.IsNullOrEmpty(txtUserPK.Text)? null:
                   Int32.Parse(txtUserPK.Text.ToString());
      UserFactory.Save(userId , txtUsername.Text, txtPassword.Text, 
                      txtEmail.Text, ddlStatus.SelectedValue);  
      jsMsgBox("Successfully added new user");            
      Response.Redirect(
          ConfigurationManager.AppSettings["AdminLink"], true);         
}

然后将Save参数处理放在Factory中  (或在某处的另一种方法

.. In UserFactory...
 Save(int? userId, string userName, string password, 
         string eMail, string selvalue)
 {
     // code to process input parameters and save/update user
     userName = userName.Trim().ToLower();
     password = password.Trim().ToLower();
     eMail    = eMail.Trim().ToLower();
     selvalue = selvalue.Trim().ToLower();
     IUser user = userId.HasValue?
                    UserFactory.getInstance().createUser(
                            userId.Value, username, password, 
                            email,status):
                    UserFactory.getInstance().createUser(
                            username, password, 
                            email, status);
     try { user.Save(); }
     catch(DBException dbX)  //   catch/rethrow Database exception 
                             //   as custom expcetion here
     {
         throw new MyCustomAppException(
                 "Save User failed: + dbX.Message",
                 dbX);
     }  
 }

并将异常处理放在Web表单的主要入口点......

public partial class MyWebPage:  System.Web.UI.Page     
{
    static void Page_Load(object sender, EventArgs e)         
    {
         try 
         {
             // asp.Net Page Load code here ...
         }
         catch(MyMainCustomApplicationException X)
         {
             jsMsgBox("An Error was encountered: " + X.Message);  
             lblInfo.Text = X.Message;        
             lblInfo.Visible = true;
         }
         catch(Exception eX) 
         {  
              // Maybe Log it here...
              throw;   // Important to retrhow all unexpected exceptions to
                       // MAKE web page crash !! as you have no idea
                       // whether web app is in consistent state now.
         }
    }
}

答案 6 :(得分:0)

在方法中封装变量赋值以便重用

private IUser GetUser()
{

    string username = FormatText(txtUsername.Text)
    string password = FormatText(txtPassword.Text);
    string email = FormatText(txtEmail.Text);       
    string status = ddlStatus.SelectedValue.Trim();
    if(txtUserPK.Text!=string.empty){
        int userPK = Int32.Parse(txtUserPK.Text);
        IUser user = UserFactory.getInstance().
                         createUser(userPK, username, password, email, status);
    }
    else
    {
        IUser user = UserFactory.getInstance().
                         createUser(username, password, email, status);
    }
    return user;
}

private string FormatText(string input)
{
    return input.Trim().ToLower();
}

答案 7 :(得分:0)

此外,您还会获取用户/密码/电子邮件/状态两次。我将这四个至少封装到一个具有单个Get方法或属性的类中。如果它们在表单上,​​我将它们封装在用户控件中,将各个值公开为用户控件的属性。

不重构,但仍然:

我摆脱了try / catch块。您向用户显示的消息不是他们想要看到的,也不能做任何事情。最好让它传播并由ASP.NET记录。使用自定义错误页面为用户提供更漂亮的内容,例如“抱歉,我们蠢蠢欲动”。