Чем представление Java о статическом отличается от C #? - PullRequest
6 голосов
/ 04 февраля 2009

Я читаю книгу Джоша Блоха Эффективная Java , и он предлагает использовать шаблон проектирования строителя при создании объектов, которые имеют большое количество членов. Из того, что я вижу, это не ванильный дизайн, а его вариация. Мне скорее нравится его внешний вид, и я пытался использовать его в веб-приложении на C #, которое я пишу. Этот код написан на Java и отлично работает

public class Property { 

    private String title;
    private String area;

    private int sleeps = 0;

    public static void main(String[] args) {

        Property newProperty = new Property.Builder("Test Property").Area("Test Area").Sleeps(7).build();

    }

    private Property(Builder builder) {
        this.title = builder.title;
        this.area = builder.area;
        this.sleeps =builder.sleeps;
    }

    public static class Builder{
        private String title;
        private String area;

        private int sleeps = 0;

        public Builder (String title){
            this.title = title;
        }

        public Builder Area(String area){
            this.area = area;
            return this;
        }

        public Builder Sleeps(int sleeps){
            this.sleeps = sleeps;
            return this;
        }

        public Property build() {
            return new Property(this);
        }
    }   
}

Когда я помещаю это в то, что я считаю C # эквивалентом

 public class Property
    {
    private String title;
    private String area;

    private Property(Builder Builder)
    {
        title = Builder.title;
        area = Builder.area;
    }


    public static class Builder
    {
        // Required parameters
        private String title;
        private String area;

        // Optional parameters
        private int sleeps = 0;

        public Builder(String val)
        {
            this.title = val;
        }

        public Builder Area(String val)
        {
            this.area = val;
            return this;
        }

        public Builder Sleeps(int val)
        {
            this.sleeps = val;
            return this;
        }

        public Property build()
        {
            return new Property(this);
        }
    }
    }

Тогда я получаю предупреждения компилятора. Большинство из них «не могут объявлять члены экземпляра в статическом классе».

Итак, мой вопрос, во-первых, что я пропустил? Если я что-то пропустил, могу ли я сделать это так, как рекомендует Джош Блох, но в C #, и, наконец, и это тоже важно, это безопасно для потоков?

Ответы [ 9 ]

13 голосов
/ 04 февраля 2009

public static class в Java означает, что вы определяете статический вложенный класс. Это означает, что он логически содержится в другом классе, но его экземпляры могут существовать без ссылки на его внешний класс. Нестатический вложенный класс называется «внутренним классом», и его экземпляры могут существовать только в отношении экземпляра внешнего класса.

В C # a static class это тот, который не может быть создан и, следовательно, не может иметь никаких нестатических членов. В Java нет прямого языкового эквивалента этой конструкции, но вы можете легко предотвратить создание экземпляров Java-класса, предоставив только частный конструктор.

Краткий обзор Java:

  • Все классы, определенные внутри другого класса, являются «вложенными классами»
  • вложенные классы, которые не static, называются внутренними классами
  • экземпляры внутренних классов могут существовать только по отношению к экземпляру внешнего класса
  • static вложенные классы не имеют отдельного имени
  • static вложенные классы в значительной степени независимы от своего внешнего класса (за исключением некоторых привилегированных прав доступа).

Я был бы рад, если бы какой-нибудь гуру C # рассказал нам, как обрабатываются внутренние / вложенные классы в C # /. NET.

3 голосов
/ 04 февраля 2009

Я думаю, что вы можете достичь почти такого же эффекта, если создадите Builder в качестве класса верхнего уровня (поскольку это именно то, что есть в Java) и создадите фабричный метод для получения конструктора, чтобы сохранить конструктор частным ( в свою очередь позволит вам вернуть экземпляры подклассов, если это необходимо).

Смысл в том, чтобы позволить строителю выполнить шаги, необходимые для создания объекта.

Итак (не зная о C #, вы можете попробовать что-то вроде этого)

// My naive C# attempt:P

public class Property 
{

    public static void main( String []args ) 
    {
         Property p = Property.buildFrom( new Builder("title").Area("area").Etc() )
    }
    public static Property buildFrom( Builder builder ) 
    {
        return new Propert( builder );
    }

    private Property ( Builder builder ) 
    {
        this.area = builder.area;
        this.title = builder.title;
        // etc. 
    }
}
public class Builder 
{
    public Builder ( String t ) 
    {
       this.title = t;
    }

    public Builder Area( String area )
    {
       this.area = area;
       return this;
    }
    // etc. 
}

Весь смысл наличия Builder в качестве статического внутреннего класса свойств состоит в том, чтобы создать высокую связь между ними (как будто они где-то один). Вот почему метод сборки в Builder вызывает закрытый конструктор «Property».

Вероятно, в C # вы могли бы использовать альтернативный артефакт для создания той же связи.

2 голосов
/ 04 февраля 2009

saua имеет правильный ответ, но я бы хотел уточнить ваш пример, в частности:

В версии C # вы должны удалить ключевое слово static из внутреннего класса. Это не означает то же самое, что и версия Java, и действительно, эффект, который она имеет в версии Java, заключается в поведении normal для внутренних классов в C #.

2 голосов
/ 04 февраля 2009

В Java вложенный класс по умолчанию связан с конкретным экземпляром содержащего его класса. Экземпляр вложенного класса может обращаться к переменным и методам содержащего экземпляра. Если у вложенного класса есть ключевое слово «static», то он не связан с экземпляром внешнего класса. В этом смысле Блох использует ключевое слово «static» в классе Builder.

«Статический» означает что-то другое, когда применяется к вложенному классу в C #. Я не знаю, какое ключевое слово вы бы использовали в C #, или даже если это необходимо. Вы пытались исключить ключевое слово static из определений классов?

Использование «статического» в определениях классов Java обсуждается в пункте 18 «Эффективной Java».

1 голос
/ 04 февраля 2009

Я не уверен, что делает Java с объявлением статического класса, но в C # статический класс - это класс, который имеет только члены уровня класса и, по определению, не может быть реализован в экземпляре. Это как старая разница между классом и модулем в VB.

0 голосов
/ 05 февраля 2009

Предполагая, что ваш класс имеет общедоступные свойства, соответствующие членам компоновщика, вам не нужен шаблон компоновки Блоха в C #. Вы можете использовать Инициализаторы объектов :

public class Property 
{ 

    public String Title {get; set};
    public String Area {get; set};
    public int Sleeps {get; set};

    public static void main(String[] args)
    {

        Property newProperty = new Property {Title="Test Property", Area="Test Area", Sleeps=7};

    }
}

Это будет невозможно, если вам нужно больше инкапсуляции.

0 голосов
/ 04 февраля 2009

Чтобы ответить на несколько комментариев о том, как получить поведение внутреннего класса Java в C #, может показаться, что ссылка на включающий класс должна быть передана в конструкторе внутреннего класса (из быстрого Google - C #, возможно, с тех пор добавленного возможность).

public class Outer 
{

...
void SomeMethod() {
    Inner             workerBee=new Inner(this);
    }
...

    class Inner
    private Outer outer;
    {
    Inner(Outer out) {
        outer=out;
        }
    }
}

Так что C # просто делает явным то, что Java делала неявно, в том числе явно нуждалась в ссылке для доступа к членам внешнего класса.

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

0 голосов
/ 04 февраля 2009

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

0 голосов
/ 04 февраля 2009

Я не знаю, почему C # жалуется, но я могу сказать, что код является поточно-ориентированным. Если бы вы создавали два или более экземпляров Property одновременно, каждый в своих потоках, у вас не возникло бы никаких проблем.

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