Tell-Don't-Ask principle for finding distance within same class - java

From what I understand of the Tell-Don't-Ask principle, my other classes should not be able to call upon the data stored in any other class. Hence, getters are frowned upon under this principle. In order to prevent access into the data, they are normally written as:
class Point {
private final double x;
private final double y;
}
However, if I were to implement methods like distance between 2 points, I would need to access the x and y of the other point. In this case, I would need the getter method.
class Point {
private final double x;
private final double y;
Point(double x, double y) {
this.x = x;
this.y = y;
}
private double getX() {
return this.x;
}
private double getY() {
return this.y;
}
public double distanceBetween(Point p) {
double dx = this.x - p.getX();
double dy = this.y - p.getY();
return Math.sqrt(dx * dx + dy * dy);
}
}
Wouldn't this violate the Tell-Don't-Ask principle? As now, I opened the data within the class to be accessed? Or is my understanding of the Tell-Don't-Ask principle wrong?

You are "allowed" to access the data stored in yourself as a Point. So a Point object can access data stored inside itself, but also in other Point objects.
In short, that does not violate Tell-don't-ask (I assume that is what you mean).
Also, you don't need a getter method. Fields marked "private" can be accessed from any method in the class, regardless of instances of that class. The reason for that is exactly the above.

Related

Java how to have two variables point to the same primitive object

I am writing a platform game in Java in which there are various game objects such as platforms, the player, and (eventually) enemies. I describe the position of these game objects with rectangles: x position, y position, width, and height. However, I would also like to add in other variables to describe the position: left, top, right, and bottom. For the last two I know I will need to change them whenever x, y, width, or height gets modified, but as left and top are the same as x and y, I was wondering how I could get them to point to the same value as x and y. I think this can be done in C with the #define function, but sadly this is Java, not C.
How can I get two different variable names to point to the same value in Java such that if one changes, the other changes as well?
Edit: Here is the basics of my GameObject class:
public abstract class GameObject {
protected float x;
protected float y;
protected float right;
protected float bottom;
protected float width;
protected float height;
public float getX() {
return x;
}
public float getY() {
return y;
}
public void setX(float x) {
this.x = x;
right=this.x+width;
}
public void setY(float y) {
this.y = y;
bottom=this.y+height;
}
//A bunch of other getters/setters
//Subclasses must have render (for displaying graphics) and tick (mainly for updating position) functions.
public abstract void render(Graphics g);
public abstract void tick();
}
What I would like to do is add in two more variables:
protected float left = x;
protected float top = y;
and have these refer to the same primitive as x and y (not copy the primitives). This, apparently, does not seem possible. Thanks for your answers!
This can't be done in Java in the sense that you mean it. You can have two object references that point to the same object, but if you have a normal primitive variable, those are always distinct and don't refer to each other. You can make an object to hold a primitive, have two different references to that same object, and a change to the contents of that object through one reference will be reflected in the other, but you cannot have an int x and and int y where writing x = 10 will make y == 10.
If you really need something behaving like a reference to a primitive, you need to create an object holding that primitive value and then share the "holder" object.
However, I don't think this is the best way to tackle your problem.
As I understand your game objects, they can be entirely described with x, y, height and width variable. left, top, right and bottom on the other hand, are values that can derived from the four basic ones.
In fact, it would be possible to have a game object containing only x, y, height and width and to compute the other four values outside of the object whenever they are needed. Such an object could look like this :
public class GameObject {
private int x, y, height, width;
public int getX() { return x; }
public int getY() { return y; }
public int getHeight() { return height; }
public int getWidth() { return width; }
public void setX(int x) { this.x = x; }
public void setY(int y) { this.y = y; }
public void setHeight(int height) { this.height = height; }
public void setwidth(int width) { this.width = width; }
}
Notice that the actual variables are private and only readable through getters. This helps to avoid the use of a variable reference later on.
Now, to have an easy and unique way to access to left, top, right and bottom, while you could add four variables and keep them in sync with the four other variable already present, I think it is not the best way to do it.
I suggest that you just compute them on the fly inside slightly smarter-than-average getters. It would look like that :
public class GameObject {
// getters and setters omitted for brevity
private int x, y, height, width;
public int getLeft() {
return x;
}
public int getRight() {
// assuming x increase toward the right
return x + width;
}
public int getTop() {
return y
}
public int getBottom() {
// assuming y increase toward the bottom
return y + height;
}
}
This will also help if you need to create some special update methods, like moveRight(int delta), scale(double factor) since you will only need to apply changes to the basic variables and not the values that are derived from them.
int/integer is passed by value, not by reference in java.
You can define a new class, For example,
public class Position {
int x;
int y;
}
Let two variables point to the same instance of Position.
In java there are two types of variables.
1.Primitive types
2.Reference types
You need to use reference type variable if you want to refer the same object through different variables.
In your case for gaming application those parameters might change frequently.
So if all the time values, left and top are same as x and y, you can use use one variable to represent the both parameters which saves memory.
e.g : for left and x use one variable.
Or else using java OOP concepts,
you can make those x, y, left, top parameters private and assign getters and setters for those.
public int setX(int x){
this.x =x;
}
public setLeft(int left){
this.left = left;
}
public int setY(int y){
this.y =y;
}
public setTop(int top){
this.top= top;
}
public setXnLeft(int xnleft){
setX(xnleft);
setleft(xnleft);
}
public setYnTop(int yntop){
setY(yntop);
setTop(yntop);
}
This can easily be done by creating a new Class. Java is object-oriented, so, basically, everything is about classes and it's instances. Take a look at an example below:
class GameObject
{
//Instance variables
//(all objects of this class will have their own)
int x;
int y;
int width;
int height;
//Constructor
//(you call a constructor when creating a new object)
GameObject(int x, int y, int width, int height)
{
//Here you are assigning the values received to the instance variables (marked with "this", that represents the current object)
this.x = x;
this.y = y;
this.width = width;
this.height = height;
}
//This method will return the ordinate ("y") of the object's top position (assuming the "y axis" points down)
int getTop() {
return (y - height/2);
}
}
After creating the class GameObject, you can create instances (objects) of it. Look below:
GameObject player = new GameObject(0, 0, 50, 50); //creates a new object with coordinates (0,0), width = 50 and height = 50
GameObject enemy1 = new GameObject(30, 50, 100, 100);
//Getting the "x" position of the player and the monster
System.out.println("Player X = " + player.x);
System.out.println("Enemy1 X = " + enemy1.x);
//Get the top position "y"
System.out.println("Player top = " + player.getTop());
//Change player's "y"
player.y = 10;
//Get player's top position again
System.out.println("Player top = " + player.getTop()); //it will have changed, since "y" was changed.
Oracle has a really good lesson about Object-Oriented Programming, you should check it out here. The C language is structured, while Java is Object-Oriented, these are two different paradigms. I hope this was of help. Cheers!

Initializing an object without new operator in java

Whats the difference between these two constructors.
Circle (Point2D center, double radius) {
this.center = center;
this.radius = radius;
}
Circle (Point2D center, double radius) {
this.center = new Point2D(center.getX(), center.getY());
this.radius = radius;
}
Heres the Point2D class. Both versions of the constructors are working just fine. I am just confused whats the difference.
class Point2D {
double x;
double y;
Point2D () {
x = 0;
y = 0;
}
Point2D (double x, double y) {
this.x = x;
this.y = y;
}
void setX (double x) {
this.x = x;
}
void setY (double y) {
this.y = y;
}
void setXY (double x, double y) {
this.x = x;
this.y = y;
}
double getX () {
return x;
}
double getY () {
return y;
}
double distance (Point2D p) {
double x1 = p.getX();
double y1 = p.getY();
return Math.sqrt(Math.pow(x1 - x, 2) + Math.pow(y1 - y, 2));
}
double distance (double x, double y) {
return Math.sqrt(Math.pow(x - this.x, 2) + Math.pow(y - this.y, 2));
}
}
Also the Circle class has 2 fields center and radius. center is type Point2D and radius is type double. I tried compiling and running both versions of the constructor. Both works well. So i am confused which one will be better to use and why, also the difference because in first one i havent used the new operation to initialize the center object.
second constructor uses defensive copy (witch is produced by Point2D constructor call) of the original center instance to prevent further mutation (changes) of the input instance that may be very confusing and produce bugs
So i am confused which one will be better to use and why
the second approach is more safe because your Point2D class is mutable. It uses more memory (to hold additional defensive copy) but in real complex projects there are more pros for this design practice than cons.
If you can make Point2D class immutable then it will be ok to use the first constructor.
The second constructor creates a new Point instance - this.center = new Point2D(center.getX(), center.getY()); instead of keeping a reference to the instance passed to it. This means that if the passed center is later modified, the changes doesn't affect the Circle instance.
The second constructor is usually safer, since it has a truly private Point instance as the center of the Circle, while the first constructor shares the center with the caller of the constructor.
You can see the difference with this code :
Point2D point = new Point2D(10.0, 20.0);
Circle circle = new Circle (point, 4.0);
point.setX (5.0);
System.out.println(circle); // assuming you override toString to display the properties
// of the Circle
If you use the first constructor, after this code is executed, your circle will have a center of (5.0,20.0), while if you use the second constructor, the circle will have a center of (10.0,20.0);
Point2D is not immutable, i.e. has properties which can be changed after the point was constructed.
The first constructor of Circle just uses the Point2D object - now the caller could change the point object which would also affect the circle.
The second constructor of Circle makes a copy of the Point2D object. If the circle keeps the point object private it cannot be changed from outside.
this.center = center, you using parameter of center object.
this.center = new Point2D(center.getX(), center.getY()), you create new object of Point2D with parameter center value.

Method takes another object as a parameter

I am doing homework for java programming. I am asked to write a method that returns a distance between two points. I should use given formula that distance = square root((x2 - x1)*(x2 - x1) +(y2 - y1)*(y2 - y1)).
In the below codes, an object a will be contained current coordinate x1 and y1 and b will be coordinate x2 and y2, passed to move at some where.
How can I write the method in this class without having other classes and other elements such as x2, y2? In the objects there are two values but how can I assign each to x1 and x2, and y1 and y2? I found definition of vector for java but I am not sure it is applicable for this. Does anybody have an idea?
public class MyPoint{
private int x;
private int y;
}
public MyPoint(int x, int y){
this.x = x;
this.y = y;
}
public int distanceTo(MyPoint a, MyPoint b){
MyPoint.x1 = a;
MyPoint.y1 = a;
MyPoint.x2 = b;
MyPoint.y2 = b;
double distance = Math.sqrt((x2-x1)*(x2-x1) + (y2-y1)*(y2-y1));
return distance;
}
}
The distanceTo method should only take one parameter, a MyPoint object, not two parameters:
public double distanceTo(MyPoint other) {
// ...
}
The first object of the comparison will be the current object, the one whose method is being called.
Then in the method body you compare the current object's fields, the this.x and this.y with the x and y values of the object passed in to the method's parameter, other.x and other.y.
Also, the method probably should return a double, not an int as you have it defined.
Regarding,
How can I write the method in this class without having other classes and other elements such as x2, y2?
I'm not sure exactly what you mean by this.
You don't need to declare MyPoint.x1 = a. That isn't really doing anything. Instead you can reference the points such as a.x or b.y.
Additionally you should make sure that your return type is what you want.
EDIT: Hovercraft has essentially said the same as I did but a little nicer.
public class Point
{
int x,y;
public Point(int x, int y)
{
this.x = x;
this.y = y;
}
public static double distance(Point a, Point b)
{
return Math.sqrt((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y));
}
public static void main(String[] args)
{
Point a = new Point(0,0);
Point b = new Point(3,5);
System.out.println(distance(a,b));
}
}

Re-using getX() getY() in a mouseclick-event handler

This is a long question. I've tried to make it more concise but I think you need all the info to assist.
Here's a summary:
I'm trying to capture consecutive clicks as endpoints. I'll draw line2D objects between these points. I have a listener that sends x and y values from click events to a helper class. I'll never have more than two points, so the helper class only has firstPoint and secondPoint members. I get the clicks and send the co-ordinates to the helper class using evt.getX() and evt.getY(). The helper creates the points, but firstPoint ends up with the same co-ords as secondPoint. My detail on what's going on can be found below the code blocks.
Here's the code in my mouse click handler:
public class Dashboard extends javax.swing.JFrame {
public static ClickMaster myClicks = new ClickMaster();
public static boolean drawing = false;
private MyPoint firstPoint = new MyPoint();
private MyPoint secondPoint = new MyPoint();
.
.
.
private void MyDrawingPanelMouseClicked(java.awt.event.MouseEvent evt) {
if (firstPoint.getPointType().equals(MyPoint.PointType.NULL)) {
drawing = !drawing;
firstPoint = myClicks.parseClick(evt.getX(), evt.getY(), drawing);
} else if (drawing){
drawing = !drawing;
secondPoint = myClicks.parseClick(evt.getX(), evt.getY(), drawing);
myClicks.parsePoints(firstPoint, secondPoint);
}
}
Here's the helper class that returns points:
public class ClickMaster {
MyPoint anyPoint = new MyPoint();
public ClickMaster() {
anyPoint.setPointType(MyPoint.PointType.NULL);
}
public MyPoint parseClick(double x, double y, boolean firstClick) {
if (firstClick) {
anyPoint.setPointType(MyPoint.PointType.ANCHOR);
} else {
anyPoint.setPointType(MyPoint.PointType.END);
}
anyPoint.setX(x);
anyPoint.setY(y);
return anyPoint;
}
And here's my implementation of Point2D objects, in case it's relevant:
public class MyPoint extends Point2D {
public enum PointType {
ANCHOR, END, SOLO, NULL
};
double x;
double y;
PointType pointType;
public MyPoint(PointType pType, double x, double y) {
this.x = x;
this.y = y;
this.pointType = pType;
}
public MyPoint() {
this.x = 0.0;
this.y = 0.0;
this.pointType = PointType.NULL;
}
+ standard getters/setters as you would expect.
debugging shows that
firstPoint = myClicks.parseClick(firstX, firstY, drawing);
results in a point with the x and y values of the mouse event. This is expected.
Likewise,
secondPoint = myClicks.parseClick(evt.getX(), evt.getY(), drawing);
Results in a point with the x and y values of the second click. Also expected.
However, when I call
myClicks.parsePoints(firstPoint, secondPoint);
I see that firstPoint and secondPoint have the same x,y values.
I'm not sure but I believe it's because both firstPoint and secondPoint are getting their x and y values from the mouse evt. I think I need to put values of type double for x's and y's in to firstPoint and secondPoint as opposed to a reference to the double value returned from the mouse event by getX() and getY().
I just don't know how to make it happen.
Also, if there's a much better way to capture consecutive clicks and translate them to endpoints for shapes, I would welcome the feedback.
Actually, your problem is anyPoint. Since you only have one instance of ClickMaster, and anyPoint is only initialized once, you're returning a reference to the same object no matter how many times you call parseClick. ParseClick needs to create a new MyPoint every time it's called and return that.

How can I move a point and print the new position?

I'm new to Java and I received an assignment that asks me to write a class called PointerTester that has two Points as instance variables. I need to initialize one of these at coordinate (0.0,0.0) and one at (10.0,12.0). Then I need to move each point by +2.0 in x and -3.0 in Y, query the coordinates of the points, and print out the values.
So far I have this:
public class PointerTester{
/*instance variables*/
private double pointOneX;
private double pointOneY;
private double pointTwoX;
private double pointTwoY;
private double deltaX;
private double deltaY;
/*constructor to initialize*/
public PointerTester (){
pointOneX = 0.0;
pointOneY = 0.0;
pointTwoX = 10.0;
pointTwoY = 12.0;
deltaX = 2.0;
deltaY = -3.0;
}
/*constructor to initialize to specific value*/
PointerTester(double pointOneX, double pointOneY, double pointTwoX, double pointTwoY){
this.pointOneX = pointOneX;
this.pointOneY = pointOneY;
this.pointTwoX = pointTwoX;
this.pointTwoY = pointTwoY;
}
/*command to change value*/
public void moveBy(double deltaX, double deltaY){
this.pointOneX = this.pointOneX + deltaX;
this.pointOneY = this.pointOneY + deltaY;
this.pointTwoX = this.pointTwoX + deltaX;
this.pointTwoY = this.pointTwoY + deltaY;
}
/*Queries*/
public double getOneX(){
return pointOneX;
}
public double getOneY(){
return pointOneY;
}
public double getTwoX(){
return pointTwoX;
}
public double getTwoY(){
return pointTwoY;
}
/*print values*/
public static void main(String[] args){
PointerTester pointOne = new PointerTester();
PointerTester pointTwo = new PointerTester();
System.out.println("Point One after move (" + pointOne + ")");
System.out.println("Point Two after move (" + pointTwo + ")");
}
}
I cannot figure out how to correctly output the values or if I am completely wrong in working on this problem.
Edit It seems I needed to use this code that I at first thought was supposed to be separate
public class Point{
public double x;
public double y;
public Point(double x, double y){
this.x = x;
this.y = y;
}
public void setX(double x){
this.x = x;
}
public void setY(double y){
this.y = y;
}
public double getX(){
return x;
}
public double getY(){
return y;
}
}
How do I incorporate this into my code?
I think to get started you should have a separate class called "Point" that encapsulates an X and Y value, and includes a "moveBy" method. It could also implement "toString()" such that "System.out.println" will print something nice for it. [Edit: Or just use java.awt.Point.]
Beyond that, I'll leave that for you to do as your homework.
You might want to use some Point objects.
Point p1 = new Point();
Point p2 = new Point(10,12);
you can then use the setLocation or translate methods found in the point class. Maybe the whole thing would look something like this? Hope this helps.
main(){
//make some points
Point p1 = new Point();
Point p2 = new Point(10,12);
//move our points
p1.translate(2,-3);
p2.translate(2,-3);
//print our points
System.out.println(p1);
System.out.println(p2);
}
You can implement the toString method. There are examples here:
http://www.javapractices.com/topic/TopicAction.do?Id=55
You're trying to print the PointerTester object instead of the values contained within. System.out.println(pointOne.getOneX()) should at least stop throwing exceptions and allow you to print correctly.

Categories