Реализация одного и того же класса, только другой родитель, как с этим бороться? - PullRequest
5 голосов
/ 17 января 2011

У меня есть два класса, которые определены следующим образом:

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
   ///
}

Реализация этих классов точно такая же, поэтому я хочу удалить это дублирование, но я не знаю, как это сделать.

Можете ли вы показать мне, как это сделать?

Ответы [ 4 ]

3 голосов
/ 17 января 2011

Точка отключения - нужен ли вам доступ к закрытым переменным какого-либо из этих классов или к свойствам, специфичным для них.

Когда вы хотите инкапсулировать и обмениваться поведением, вы используете шаблон команды. Это выглядит примерно так:

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);
        }
    }
}

Это позволяет вам инкапсулировать и извлекать функциональные возможности ... ограничение, конечно, состоит в том, что вы не можете получить доступ к закрытым или защищенным элементам, или элементам, специфичным для RoleButton, и т. Д., Поскольку вам необходимо передать общую базу для команда. Неспособность получить доступ к RoleButton / RoleImageButton-специфичным членам должна быть проблемой; Ваш код не может быть обычным кодом, если он использует что-то конкретное для любого из них:)

Если вам нужен доступ к закрытым / защищенным членам, вам необходимо создать интерфейс, который предоставляет свойства, и реализовать его отдельно для RoleButton и RoleImageButton, и передать этот интерфейс команде ... но тогда вы в основном заставляя эти свойства быть публичными, и делая их доступными для других классов. Если вам абсолютно необходимо это сделать, я могу дать вам пример кода, чтобы показать вам, как это сделать, но на самом деле это не очень хорошая идея.

Что вам действительно нужно, так это множественное наследование, концепция, которую C # не поддерживает.



EDIT

Есть два способа обрезать эту кошку ... Я бы порекомендовал первый, который заключается в том, чтобы инкапсулировать переменные, которые вы собираетесь изменить в вашей команде, и передать его как параметр, как таковой:

//  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
    }

}

В качестве альтернативы, сделайте класс Roles структурой и передайте его по ссылке. Это удерживает вас от раскрытия ваших ролей, позволяя вам сохранять их защищенными. Все остальное из написанного мной кода шаблона команды используется как есть.

Второй подход даже не стоит упоминать ... Я откажусь от него под принуждением, но это такая плохая идея, я бы не хотел продвигать его, если его не пытали из-за меня. : D

HTH,
Джеймс

1 голос
/ 17 января 2011

Можете ли вы иметь класс RoleButton, который охватывает другие типы кнопок?

Если Button и ImageButton оба имеют общую базу или реализуют интерфейс, такой как IButton, у вас может быть что-то вроде этого:

class RoleButton : IButton
{
  private Button _realButton;

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

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

Таким образом, вы не будете дублировать свой код RoleButton:

var roleButton = new RoleButton(myButton);
var roleImageButton = new RoleButton(myImageButton);
1 голос
/ 17 января 2011

Я бы создал BaseButton класс, производный от Button.Если есть какие-либо изменения, характерные для каждой кнопки, то производная от BaseButton выглядит следующим образом:

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";
   }
}
0 голосов
/ 17 января 2011

Вы можете использовать шаблон T4 . Это позволит вам иметь один файл (шаблон), содержащий реализацию один раз , и он будет генерировать два класса с идентичными реализациями для вас. (Конечно, код все равно будет дублироваться в скомпилированной сборке, но, по крайней мере, этой проблемы обслуживания больше не будет поддерживать их синхронизацию.)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...