Вопрос

Предположим, у меня есть класс "Application".Для инициализации требуются определенные настройки в конструкторе.Давайте также предположим, что количество настроек настолько велико, что возникает необходимость поместить их в отдельный класс.

Сравните следующие две реализации этого сценария.

Реализация 1:

class Application 
{
   Application(ApplicationSettings settings) 
   {
       //Do initialisation here
   }
}

class ApplicationSettings 
{
   //Settings related methods and properties here
}

Реализация 2:

class Application 
{
   Application(Application.Settings settings) 
   {
       //Do initialisation here
   }

   class Settings 
   {
      //Settings related methods and properties here
   }
}

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

Теперь просто представьте, что сам класс Settings, в свою очередь, имел какой-то аналогично "связанный" класс, и этот класс, в свою очередь, тоже это делал.Пройдите только три таких уровня, и именование класса выйдет из-под контроля в случае "не вложенности".Однако, если вы гнездитесь, все по-прежнему остается элегантным.

Несмотря на вышесказанное, я читал, как люди говорили в StackOverflow, что вложенные классы оправданы только в том случае, если они не видны внешнему миру;это в том случае, если они используются только для внутренней реализации содержащего их класса.Часто цитируемое возражение заключается в раздувании размера исходного файла, содержащего класс, но partial classes - идеальное решение этой проблемы.

Мой вопрос в том, почему мы с опаской относимся к "общедоступному" использованию вложенных классов?Есть ли какие-либо другие аргументы против такого использования?

Это было полезно?

Решение

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

public class Outer
{
    private Outer(Builder builder)
    {
        // Copy stuff
    }

    public class Builder
    {
        public Outer Build()
        {
            return new Outer(this);
        }
    }
}

Это гарантирует, что только способ создания экземпляра внешнего класса - через конструктор.

Я очень часто использую этот шаблон в моем порте протокольных буферов C #.

Другие советы

Вы можете использовать пространства имен, чтобы связать вещи, которые ... связаны.

Например:

namespace Diner
{
    public class Sandwich
    {
        public Sandwich(Filling filling) { }
    }

    public class Filling { }
}

Преимущество этого по сравнению с использованием классов, как если бы они были пространствами имен, заключается в том, что вы можете дополнительно использовать using на вызывающей стороне для сокращения вещей:

using Diner;

...

var sandwich = new Sandwich(new Filling());

Если вы используете класс Sandwich так, как если бы это было пространство имен для Filling , вы должны использовать полное имя Sandwich.Filling для обратитесь к Заполнение .

И как ты будешь спать по ночам, зная это?

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

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

public class OrderViewModel
{
public int OrderId{ get; set; }
public IEnumerable<Product> Products{ get; set; }

public class Product {
public string ProductName{ get; set; }
public decimal ProductPrice{ get; set; }
}

}

Я использую его, потому что не хочу, чтобы класс Product использовался повторно снаружи, потому что он настроен только для той конкретной модели представления, которая его содержит. Но я не могу сделать это частным, потому что свойство Products является публичным.

В основном я использую вложенные классы для точной настройки доступа к вложенному классу и / или контейнеру.

Следует помнить одну вещь: определение вложенного класса в основном является членом класса и будет иметь доступ ко всем закрытым переменным контейнера.

Вы также можете использовать это для управления использованием определенного класса.

Пример:

public abstract class Outer
{
  protected class Inner
  {
  }
}

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

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top