создание - что такое объект в java




Структурировать объекты в Java (14)

Не используйте public поля

Не используйте public поля, когда вы действительно хотите обернуть внутреннее поведение класса. Возьмите java.io.BufferedReader например. Он имеет следующее поле:

private boolean skipLF = false; // If the next character is a line feed, skip it

skipLF читается и записывается во всех методах чтения. Что делать, если внешний класс, работающий в отдельном потоке, злонамеренно модифицировал состояние skipLF в середине чтения? BufferedReader определенно пойдет на уступку.

Использовать public поля

Возьмите этот класс Point например:

class Point {
    private double x;
    private double y;

    public Point(double x, double y) {
        this.x = x;
        this.y = y;
    }

    public double getX() {
        return this.x;
    }

    public double getY() {
        return this.y;
    }

    public void setX(double x) {
        this.x = x;
    }

    public void setY(double y) {
        this.y = y;
    }
}

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

Point a = new Point(5.0, 4.0);
Point b = new Point(4.0, 9.0);
double distance = Math.sqrt(Math.pow(b.getX() - a.getX(), 2) + Math.pow(b.getY() - a.getY(), 2));

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

class Point {
    public double x;
    public double y;

    public Point(double x, double y) {
        this.x = x;
        this.y = y;
    }
}

Point a = new Point(5.0, 4.0);
Point b = new Point(4.0, 9.0);
double distance = Math.sqrt(Math.pow(b.x - a.x, 2) + Math.pow(b.y - a.y, 2));

Чистота!

Но помните: не только ваш класс должен отсутствовать в поведении, но он также не должен иметь никаких причин для поведения в будущем.

Это полностью против Java-способа создания объектов типа struct?

class SomeData1 {
    public int x;
    public int y;
}

Я вижу класс с аксессуарами и мутаторами, которые больше похожи на Java.

class SomeData2 {
    int getX();
    void setX(int x);

    int getY();
    void setY(int y);

    private int x;
    private int y;
}

Класс из первого примера нотационально удобен.

// a function in a class
public int f(SomeData1 d) {
    return (3 * d.x) / d.y;
}

Это не так удобно.

// a function in a class
public int f(SomeData2 d) {
    return (3 * d.getX()) / d.getY();
}

Re: aku, izb, John Topley ...

Остерегайтесь проблем с изменчивостью ...

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

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

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

Если у вас есть общедоступные поля, подумайте о том, чтобы сделать класс доступным только для чтения. Добавьте поля в качестве параметров в конструктор и пометьте поля final. В противном случае убедитесь, что вы не подвергаете внутреннее состояние, и если вам нужно построить новые экземпляры для возвращаемого значения, убедитесь, что он не будет называться чрезмерно.

Смотрите: « Эффективная Ява » Джошуа Блоха - Пункт № 13: Благоприятность неизменности.

PS: Также имейте в виду, что все JVM в наши дни оптимизируют getMethod, если это возможно, в результате получается только одна команда чтения поля.


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


Если путь Java - это путь OO, то да, создание класса с общедоступными полями нарушает принципы вокруг скрытия информации, которые говорят, что объект должен управлять своим собственным внутренним состоянием. (Так как я не просто накладываю на вас жаргон, преимущество скрытия информации заключается в том, что внутренняя работа класса скрыта за интерфейсом - скажем, вы хотели изменить механизм, с помощью которого ваш класс struct сохранил одно из своих полей, вам, вероятно, придется вернуться и изменить любые классы, которые используют класс ...)

Вы также не можете воспользоваться поддержкой классов, совместимых с именами JavaBean, что может повредить, если вы решите, скажем, использовать класс на странице JavaServer, который написан с использованием языка выражений.

Статья JavaWorld, почему методы Getter и Setter - это статья Evil, также может вас заинтересовать, если вы не будете внедрять методы доступа и мутатора.

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


Используйте здравый смысл. Если у вас есть что-то вроде:

public class ScreenCoord2D{
    public int x;
    public int y;
}

Тогда нет смысла обманывать их в геттерах и сеттерах. Вы никогда не будете хранить координату x, y в целых пикселях любым другим способом. Getters и seters только замедлят вас.

С другой стороны, с:

public class BankAccount{
    public int balance;
}

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

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


Как и в большинстве случаев, существует общее правило, а затем есть особые обстоятельства. Если вы делаете закрытое, захваченное приложение, чтобы вы знали, как данный объект будет использоваться, вы можете использовать больше свободы для улучшения видимости и / или эффективности. Если вы разрабатываете класс, который будет использоваться публично другими, находящимися вне вашего контроля, то наклоняйтесь к модели getter / setter. Как и во всех вещах, просто используйте здравый смысл. Часто бывает нормально делать первый раунд с публикацией, а затем менять их позже на getter / seters.


Кстати, структура, которую вы даете в качестве примера, уже существует в библиотеке базового класса Java как java.awt.Point . Он имеет x и y как общедоступные поля, проверьте это самостоятельно .

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


Нет ничего плохого в этом типе кода при условии, что автор знает, что они представляют собой структуры (или передачи данных) вместо объектов. Многие разработчики Java не могут отличить хорошо сформированный объект (а не просто подкласс java.lang.Object, но истинный объект в определенном домене) и ананас. Эрго, они в конечном итоге создают структуры, когда им нужны объекты и наоборот.


Похоже, что многие люди Java не знакомы с Sun Java Coding Guidelines, которые говорят, что вполне целесообразно использовать переменную public экземпляра, когда класс по существу является «Struct», если Java поддерживает «struct» (когда нет никакого поведения).

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

Java Code Conventions от 1999 года и до сих пор не изменились.

10.1. Предоставление доступа к экземплярам и переменным класса

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

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

http://www.oracle.com/technetwork/java/javase/documentation/codeconventions-137265.html#177

http://en.wikipedia.org/wiki/Plain_old_data_structure

http://docs.oracle.com/javase/1.3/docs/guide/collections/designfaq.html#28


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

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

Кстати, по утверждению e-bartek, очень маловероятно, что IMO добавит поддержку свойств в Java 7.


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


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

На практике большинство полей имеют простые геттеры и сеттеры. Возможное решение будет выглядеть так:

public property String foo;   
a->Foo = b->Foo;

Обновление: маловероятно, что поддержка свойств будет добавлена ​​в Java 7 или, возможно, когда-либо. Другие языки JVM, такие как Groovy, Scala и т. Д., Теперь поддерживают эту функцию. - Алекс Миллер


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

Как уже отмечалось выше, есть две проблемы, с которыми вы сталкиваетесь, и они не могут быть исправлены:

  • Почти любой автоматизированный инструмент в java-мире основывается на соглашении getter / setter. Точно так же, как отмечают другие, теги jsp, конфигурация пружины, инструменты затмения и т. Д. И т. Д. ... Борьба с тем, что ваши инструменты ожидают увидеть, - это рецепт длительных сеансов, троллинг через Google, пытающийся найти этот нестандартный способ инициирования весенние бобы. На самом деле не стоит проблем.
  • После того, как у вас есть свое элегантно закодированное приложение с сотнями общедоступных переменных, вы, скорее всего, найдете хотя бы одну ситуацию, когда они недостаточны, - где вам абсолютно необходима неизменность или вам нужно вызвать какое-то событие, когда переменная будет установлена, или вы хотите бросить исключение при изменении переменной, потому что оно устанавливает состояние объекта на что-то неприятное. Затем вы застряли в незавидном выборе между загромождением своего кода с помощью специального метода везде, где переменная напрямую ссылается, имея специальную форму доступа для 3 из 1000 переменных в вашем приложении.

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

Java очень многословна, и это заманчиво. Не делай этого.


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

В стороне, даже если бы я писал этот объект как частный внутренний класс, я бы все же предоставил конструктор, чтобы упростить код для инициализации объекта. Имея 3 строки кода, чтобы получить полезный объект, когда он будет делать, это просто беспорядочно.







struct