Проблемы с модификатором класса в C # с частными классами

У меня был класс, в котором было много методов:

public class MyClass {
    public bool checkConditions() {
        return checkCondition1() &&
               checkCondition2() &&
               checkCondition3();
    }

...conditions methods

    public void DoProcess() {
        FirstPartOfProcess();
        SecondPartOfProcess();
        ThirdPartOfProcess();
    }

...process methods
}

Я выделил две «жизненно важные» области работы и решил выделить эти методы в собственные классы:

public class MyClass {
    private readonly MyClassConditions _conditions = new ...;
    private readonly MyClassProcessExecution = new ...;

    public bool checkConditions() {
        return _conditions.checkConditions();
    }

    public void DoProcess() {
        _process.DoProcess();
    }
}

В Java я бы определил MyClassConditions и MyClassProcessExecution как package protected, но я не могу этого сделать в C #.


Как бы вы это сделали на C #?

Установить оба класса как внутренние классы MyClass?

У меня есть 2 варианта: либо я определяю их внутри MyClass, имея все в одном файле, что выглядит запутанно и некрасиво, либо я могу определить MyClass как partial class, имея один файл для MyClass, другой для MyClassConditions и другой для MyClassProcessExecution.

Определяя их как внутренние?

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

Сделать их общедоступными?

Не понимаю почему, но я оставил этот вариант здесь.

Любой другой?

Назови это!

Спасибо


person devoured elysium    schedule 13.05.2010    source источник


Ответы (5)


Лучше всего, вероятно, использовать частичные классы и поместить три фрагмента кода в отдельные файлы, добавляя к одному и тому же классу. Затем вы можете сделать условный код и код процесса закрытым, чтобы только сам класс мог получить к ним доступ.

person dthorpe    schedule 13.05.2010

Для классов типа «Помощник», которые не будут использоваться вне текущей сборки, Internal - это путь, который будет использоваться, если методы будут использоваться несколькими классами.

Для методов, которые будут использоваться только одним классом, я бы просто сделал их частными для класса или использовал внутренние классы, если это действительно класс, который больше нигде не используется. Вы также можете выделить код в статические методы, если код не зависит от каких-либо (нестатических) членов вашего класса.

person dcp    schedule 13.05.2010
comment
Да, они не будут использоваться вне сборки. Но их также нельзя использовать вне самого класса :( - person devoured elysium; 13.05.2010
comment
Да, я отредактировал свой ответ, чтобы отразить эту озабоченность. Я не большой поклонник внутренних классов, потому что они имеют тенденцию загромождать код (ИМО), но если они больше нигде не используются, вы можете обосновать это здесь. - person dcp; 13.05.2010
comment
Я не вижу никаких преимуществ в разложении кода на статические методы. Способы все еще есть, в чем преимущество? - person devoured elysium; 13.05.2010
comment
Stackoverflow - ваш друг;) (stackoverflow.com / questions / 135020 /) - person dcp; 13.05.2010
comment
Я не вижу никаких преимуществ в отношении того, что просит OP. - person devoured elysium; 13.05.2010
comment
Дело в том, что всегда лучше делать методы статическими, если можно, потому что это может улучшить производительность (см. Ссылку). Поэтому каждый раз, когда я занимаюсь рефакторингом кода, я всегда стараюсь это делать. В контексте этого вопроса это не так уж и важно, но это просто хорошо, когда вы можете. Поскольку это был вопрос типа рефакторинга, я подумал, что это может быть полезно. - person dcp; 13.05.2010

Я могу определить MyClass как частичный класс, имеющий один файл для MyClass, другой для MyClassConditions и другой для MyClassProcessExecution.

Возможно, это мой опыт работы с C ++, но это мой стандартный подход, хотя я объединяю небольшие вспомогательные классы в один файл.

Таким образом, в одном из моих текущих проектов класс Product разделен между Product.cs и ProductPrivate.cs.

person egrunin    schedule 13.05.2010

Я собираюсь сделать что-то другое - проблема общедоступного / защищенного / частного не может быть решена специально этим, но я думаю, что он гораздо лучше поддается обслуживанию, чем множество вложенных внутренних классов.

Поскольку это звучит так, как будто у вас есть набор шагов в последовательном алгоритме, где выполнение одного шага может или не может зависеть от выполнения предыдущего шага. Этот тип последовательной пошаговой обработки иногда может использовать шаблон цепочка ответственности, хотя он немного изменилось от своего первоначального замысла. Сосредоточение внимания только на вашем «методе обработки», например, начиная с чего-то вроде ниже:

class LargeClass
{
public void DoProcess()
{
  if (DoProcess1())
  {
    if (DoProcess2())
    {
      DoProcess3();
    }
  }
}

protected bool DoProcess1()
{
...
}

protected bool DoProcess2()
{
...
}

protected bool DoProcess3()
{
...
}

}

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

public class AbstractStep
{
    public AbstractStep NextStep { get; set; }

    public virtual bool ExecuteStep
    {
       if (NextStep != null)
       {
         return NextStep.ExecuteStep();
       }
    }  
}

public class ConcreteStep1 : AbstractStep
{
    public bool ExecuteStep
    {
       // execute DoProcess1 stuff
       // call base
       return base.ExecuteStep();
    }
}

...

public class ConcreteStep3 : AbstractStep
{
     public bool ExecuteStep
     { 
        // Execute DoProcess3 stuff
        // call base
        return true; // or false?
      }
}

Чтобы настроить это, вы должны в некоторой части кода сделать следующее:

var stepOne = new ConcreteStep1();
var stepTwo = new ConcreteStep2();
var stepThree = new ConcreteStep3();
stepOne.NextStep = stepTwo;
stepTwo.NextStep = stepThree;

bool success = stepOne.ExecuteStep();

Это может помочь убрать раздувание кода, которое у вас есть в вашем единственном классе - в прошлом я использовал его для нескольких алгоритмов последовательного типа, и он помог хорошо изолировать каждый шаг. Очевидно, вы могли бы применить ту же идею к проверке условий (или встроить их в каждый шаг, если это применимо). Вы также можете изменить это с точки зрения передачи состояния между этапами, если метод ExecuteStep принимает параметр с каким-либо объектом состояния.

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

person Matt Jordan    schedule 13.05.2010

Создайте классы с тем же модификатором доступа, что и методы, которые вы подвергали рефакторингу. Частичные классы действительно полезны только тогда, когда у вас есть несколько человек или инструменты автоматической генерации кода, часто изменяющие одни и те же классы. Они просто действительно избегают ада слияния исходного кода, когда ваш исходный элемент управления смешивает ваш код, потому что он не может объединить несколько изменений в один и тот же файл.

person Ben Robinson    schedule 13.05.2010