статический и нестатический метод для неизменяемого класса - PullRequest
9 голосов
/ 01 февраля 2010

Учитывая определение класса ниже. Как можно решить, должны ли методы-заглушки быть статическими или нестатическими?

class Point {
    private final int x;
    private final int y;

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

    // Should the methods add(), subtract() and inverseOf() be non-static ...

    public Point add(Point point) {

    }

    public Point subtract(Point point) {

    }

    public Point inverseOf() {

    }


    // Or static?

    public static Point add(Point point1, Point point2) {

    }

    public static Point subtract(Point point1, Point point2) {

    }

    public static Point inverseOf(Point point) {

    }
}

Ответы [ 11 ]

9 голосов
/ 01 февраля 2010

Я бы пошел, например, методы. Затем у вас есть возможность сделать методы частью интерфейса и переопределить их. Вы получили бы выгоду, когда вам нужно иметь дело с 2d-точками или 3d-точками и иметь некоторый клиентский код, который на самом деле не заботится и просто должен выполнять операции с точками, реализующими интерфейс.

3 голосов
/ 01 февраля 2010

Я бы пошел на нестатические методы, которые более объектно-ориентированы (да, использование слишком большого количества статических методов нарушает преимущества таких объектов, как полиморфизм, наследование ...), даже если ваш Point неизменен. И на самом деле, это будет соответствовать способу разработки классов типа BigDecimal или BigInteger. Кроме того, статические методы затрудняют тестирование классов , поэтому я предпочитаю избегать их использования, если это возможно, особенно когда это имеет смысл.

3 голосов
/ 01 февраля 2010

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

Если вы используете статические методы, вы можете рассмотреть возможность помещения статических методов в отдельный служебный класс (PointCalculator), который содержит только статические методы. Это похоже на урок математики.

2 голосов
/ 01 февраля 2010

Семантически, статический подход, кажется, имеет немного больше смысла. Оба, конечно, будут работать, но нестатический подход отдает приоритет одной точке над другой, и, кроме того, подразумевает, что point1 (метод, для которого вызывается add) может быть изменен в результате вызова.

Как разработчик, использующий ваши классы, если бы я увидел следующее:

Point p1 = new Point(1,2);
Point p2 = new Point(2,3);

p1.Add(p2);

или ..

Point p1 = new Point(1,2);
Point p2 = new Point(2,3);

Point.Add(p1, p2);

Моя естественная склонность состоит в том, чтобы предположить, что метод add () в нестатической версии изменяет point1, добавляя результат пункта 2. При статическом подходе становится более ясным (хотя и не гарантировано!), Что метод чисто и репрезентативные точки не изменяются.

1 голос
/ 01 февраля 2010

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

Совершенно часто встречаются такие методы, как add () и subtract () для неизменяемого класса, которые возвращают новые экземпляры неизменяемого класса. Это хороший стиль для FP-подобного программирования и вполне приемлем для такого класса. (См. BigInteger или BigDecimal для хороших примеров. Не смотрите Дата или Календарь для плохих сломанных страшных примеров.:)

Хранение методов в классе позволяет вам по желанию определять интерфейсы, которые могут реализовывать эти классы, использовать шаблон Decorator или Adapter, писать определенные виды тестов и т. Д.

1 голос
/ 01 февраля 2010

Используйте статический метод, когда тело метода не зависит ни от одного конкретного экземпляра.

В качестве одного примера рассмотрим ваш add(Point, Point) метод. Вы складываете вместе два Point, которые передаются функции в качестве аргументов, и возвращаете еще один Point. Действительно ли для этого нужна внутренняя ссылка this на Point?

С другой стороны, у вас есть метод add(Point). Предположительно, это добавляет аргумент функции к экземпляру - в этом случае вам придется сделать это методом экземпляра, чтобы у вас были оба Point s.

Редактировать : Мне кажется, я неправильно понял, изначально. Оглядываясь назад, вы получаете правильные подписи как для статических, так и для нестатических реализаций. На данный момент, я бы сказал, это вопрос стиля, поскольку вы знаете, что оба будут работать правильно. Как вы хотите, чтобы ваш класс был использован? Подумайте, делает ли он код более интуитивным, скажем Point a = Point.add(b, c) или Point a = b.add(c). Лично мне нравится первое, поскольку оно говорит мне, что ни один из операндов не будет изменен.

0 голосов
/ 18 марта 2010

Из-за того, что они статичны, их сложнее тестировать! Единственный фальшивый фреймворк, который я знаю в .NET, который мог бы справиться с этим, - это TypeMock.

Если вы намерены сделать этот класс неизменным, то вы будете возвращать новые объекты Point в любом методе доступа, так что вызывайте статичность, и здесь нет особого смысла.

0 голосов
/ 01 февраля 2010

Эти методы должны быть статическими, потому что сам класс поддается созданию через конструктор и присваивает значения один раз, поскольку x и y являются окончательными. Это означает, что вы можете создавать Очки, но не манипулировать их данными в будущем. Методы Add / Substract / Etc - это служебные методы, которые не должны требовать использования экземпляра Point.

0 голосов
/ 01 февраля 2010

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

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

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

0 голосов
/ 01 февраля 2010

В вашем случае он должен быть нестатичным, если вы не измените подпись на public static Point add(Point point1, Point point2).

РЕДАКТИРОВАТЬ : Я проголосовал. Все в порядке. Я не пытался дать тривиальное предположение, например, поставить статический метод на передний план. В этом случае метод экземпляра лучше, но на самом деле нет единственного ответа. Это зависит только от ваших предпочтений.

...