Самый простой (в лоб) подход будет сделать одну структуру. Я опущу все геттеры, сеттеры и прочие Java-штуки, просто чтобы оставить код максимально простым. В целом их использовать более чем стоит.
class Rect {
public int aX;
public int aY;
public int bX;
public int bY;
public int cX;
public int cY;
public int dY;
public int dX;
}
И дальше воротить от этой структуры данных уже нужные себе вещи. Опять же я опущу все лишнее и оставлю только сам метод (например умножения).
public Rect multiply(Rect source, float amount) {
Rect result = new Rect();
result.aX = source.aX * amount;
result.aY = source.aY * amount;
result.bX = source.bX * amount;
result.bY = source.bY * amount;
result.cX = source.cX * amount;
result.cY = source.cY * amount;
result.dX = source.dX * amount;
result.dY = source.dY * amount;
return result;
}
Если хочется более "объектно-ориентированной" структуры то нужно для начала понять какие объекты в ней будут реально обладать поведением. Ну то есть например в классических примерах с кошками-собаками-животными почему-то никто не стремится делать в кошке объект Язык, который будет отвечать за конкретный "Мяу". Тут так же, если точка (как объект) не несет сама по себе никакого функционала совсем не факт что она нужна. Соответственно первое что тут просится это собрать квадрат (или если уж на то пошло - многоугольник) как просто коллекцию ребер. Тогда получится что-то такое:
class Edge {
public float aX;
public float aY;
public float bX;
public float bY;
}
class Poly extends ArrayList<Edge> {
public Poly multiply(Poly source, float amount) {
Poly result = new Poly();
for (Edge edge : source) {
Edge newEdge = new Edge();
newEdge.aX = edge.aX * amount;
newEdge.aY = edge.aY * amount;
newEdge.bX = edge.bX * amount;
newEdge.bY = edge.bY * amount;
result.add(newEdge);
}
return result;
}
}
Проблема такого подхода, как я описал выше, что точка сама по себе не существует и не может содержать логики. Например если тебе нужно будет подвигать точку на экране то реализовать эту логику будет непросто в данном случае, потому что придется искать все ребра которые задеты этим. Решить же это можно если ввести класс точек, что превратит наш код в примерно вот такой:
class Dot {
public float x;
public float y;
}
class Edge {
public Dot a;
public Dot b;
}
class Poly extends ArrayList<Dot> {
public List<Edge> edges = new ArrayList<>();
public Poly multiply(Poly source, float amount) {
Poly result = new Poly();
// Map just to remember old dots bindings
Map<Dot, Dot> newDots = new HashMap<>();
for (Dot dot : source) {
Dot newDot = new Dot();
newDot.x = dot.x * amount;
newDot.y = dot.y * amount;
result.add(dot);
newDots.put(dot, newDot);
}
for (Edge edge : edges) {
Edge newEdge = new Edge();
newEdge.a = newDots.get(edge.a);
newEdge.b = newDots.get(edge.b);
result.edges.add(newEdge);
}
return result;
}
}
Как видно, добавление новой сущности сделало весь код сложнее, а клонирование объекта куда более комплексным. Хотя теперь возможно изменять точку и не думать о том что какие-то ребра будут забыты.
В целом все структуры данных должны в первую очередь опираться на то, как эти данные будут использованы.
Этот код дан исключетельно как ответ на вопрос и на подумать, не стоит так писать в реальных приложениях. Надеюсь ответ будет полезен ;)