Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Same class implement, just only different parent, how to deal with this?

I have two classes that defined like this:

public class RoleButton: Button
{
   protected bool PrimaryRole;
    protected bool SecondaryRole;

    private string _role;
    private AuthenticatedPage CurrentPage
    {
        get { return (AuthenticatedPage)Page; }
    }

    protected UserInfo CurrentUser
    {
        get { return CurrentPage.CurrentUser; }
    }

    protected void SetRole(string role)
    {
        _role = role;
    }

    protected override void OnPreRender(EventArgs e)
    {
        base.OnInit(e);

        if (CurrentUser.IsSuperAdmin) return;
        DataTable dt = CommandController.GetButtonRoleForUserByPortalID(CurrentUser.UserID,
                                                                        ConvertUtility.ToInt32(AppEnv.PortalId()));

        if (dt.Rows.Count > 0)
        {
            if (dt.Rows.Count > 1)
            {
                PrimaryRole = ConvertUtility.ToBoolean(dt.Rows[0][_role]);
                SecondaryRole = ConvertUtility.ToBoolean(dt.Rows[1][_role]);

                if (!PrimaryRole && !SecondaryRole)
                {
                    Visible = false;
                }
                else
                {
                    Visible = true;
                }
            }
            else
            {
                PrimaryRole = ConvertUtility.ToBoolean(dt.Rows[0][_role]);
                Visible = PrimaryRole;
            }
        }
        else
        {
            Visible = false;
        }     
}


public class RoleImageButton: ImageButton
{
   ///
   ///same as above
   ///
}

The implementation of these classes are exactly the same, so I want to remove this duplication, but I don't know the technique to do this.

Can you show me the way to do this?

like image 218
Quan Mai Avatar asked Jan 17 '11 03:01

Quan Mai


3 Answers

The tripping point is whether or not you need to access private variables of any of those classes, or properties that are specific to them.

When you want to encapsulate and share behavior, you use the Command Pattern. It looks something like:

public interface ICommand {
    void ExecuteOnPreRender(WebControl control, EventArgs args);
}

//  This class encapsulates the functionality common
//  to both OnPreRender commands
public class SharedPreRenderCommand : ICommand {
    public void ExecuteOnPreRender(WebControl control, EventArgs args) {
        //  Modify the size, border, etc... any property that is 
        //  common to the controls in question
    }
}

public class RoleImageButton : ImageButton {

    private ICommand onPreRenderCommand = null;

    public void SetPreRenderCommand (ICommand command) {
        onPreRenderCommand = command;
    }

    protected override void OnPreRender(EventArgs args) {
        if (null != onPreRenderCommand) {
            onPreRenderCommand.ExecuteOnPreRender(this, args);
        }
        else {
            base.OnPreRender(args);
        }
    }
}


public class RoleButton : Button {

    private ICommand onPreRenderCommand = null;

    public void SetPreRenderCommand (ICommand command) {
        onPreRenderCommand = command;
    }

    protected override void OnPreRender(EventArgs args) {
        if (null != onPreRenderCommand) {
            onPreRenderCommand.ExecuteOnPreRender(this, args);
        }
        else {
            base.OnPreRender(args);
        }
    }
}

This allows you to encapsulate and extract functionality... the limitation, of course, is that you can't access private or protected members, or members specific to RoleButton, etc., because you have to pass a common base to the command. Not being able to access RoleButton/RoleImageButton-specific members should be a non-issue; your code can't be common code if it uses anything specific to either of these : )

If you have to access private/protected members, you would need to create an interface that exposes the properties, and implement it separately for both RoleButton and RoleImageButton, and pass that interface to the command... but then you're basically forcing those properties to be public, and making them accessible to other classes. If you absolutely need to do this, I can give you some sample code to show you how, but it's really not a good idea.

What you're really after is multiple inheritance, a concept that C# doesn't support.



EDIT

There are two ways to skin this cat... I'd recommend the first one, which is to encapsulate the variables you're going to change in your command and pass it as a parameter, as such:

//  Encapsulate these fields if you want to be PC
public class Roles {
    public bool PrimaryRole;
    public bool SecondaryRole;
}

public class RoleButton: Button {
    protected Roles buttonRoles;    
    ...
}

public class SharedPreRenderCommand : ICommand {

    public void ExecuteOnPreRender(WebControl control, Roles roles, EventArgs args) {
        //  Modify the Roles class, which the RoleButton or 
        //  RoleImageButton has a handle to
    }

}

Alternatively, make the Roles class a struct and pass it by ref. This keeps you from exposing your roles, allowing you to keep them as protected. Everything else from the command-pattern code I wrote is used as-is.

The second approach isn't even worth mentioning... I'll give it up under duress, but it's such a bad idea, I wouldn't want to promote it unless it were tortured out of me. : D

HTH,
James

like image 75
James King Avatar answered Oct 15 '22 17:10

James King


Can you have a RoleButton class that wraps around other button types?

If Button and ImageButton both have a common base or implement an interface like IButton you could have something like this:

class RoleButton : IButton
{
  private Button _realButton;

  public RoleButton(Button realButton) { _realButton = realButton; }

  // IButton implementation delegates non-role stuff to _realButton
}

That way you don't end up duplicating your RoleButton code:

var roleButton = new RoleButton(myButton);
var roleImageButton = new RoleButton(myImageButton);
like image 36
Andrew Kennan Avatar answered Oct 15 '22 18:10

Andrew Kennan


I would create a BaseButton class that derives from Button. If there are any changes specific to each button, then derive from BaseButton as follows:

public class BaseButton : Button
{
   ///
   protected override void OnPreRender(EventArgs e)
   {
      // Common base implementationi
   }         
}

public class ImageButton: BaseButton
{
   // Specific implementation
   public ImageButton()
   {
      this.Name = "ImageButton";
   }
}

public class RoleButton: BaseButton
{
   // Specific implementation
   public RoleButton()
   {
      this.Name = "RoleButton";
   }
}
like image 37
SwDevMan81 Avatar answered Oct 15 '22 17:10

SwDevMan81