简体   繁体   中英

How to create classes for geometric shapes (points, lines, square, triangle, etc.) in Ruby

We were asked to create geometric shapes via classes. We must create:

  1. A Point class.
  2. A Line class (line - when two points are connected).
  3. A square class.

I created a Point class, with accessible coordinates (2D):

class Point
  attr_accessor :x, :y
  def initialize
    @x = 10
    @y = 10
  end
  def x=(value)
    @x = value
  end
  def x()
    @x
  end
  def y=(value)
    @y = value
  end
  def y()
    @y
  end
end

And, I want to create a new point class:

p = Point.new
  p.x = 1
  p.y = 5
  print p # -> #<Point:0x007f9463089cc0>

And, as a result, I have some thing like this:

#<Point:0x007f9463089cc0>

What does this mean?

If I print px, py then I will have a understandable result:

print p.x, ", ", p.y # -> 1, 5

How can I understand this result on the screen?

Is there any use in a real programming job to create point, lines and geometric shapes?

You don't need to write the setters and getters methods:

  def x=(value)
    @x = value
  end
  def x()
    @x
  end
  def y=(value)
    @y = value
  end
  def y()
    @y
  end

This is because you can use:

attr_accessor :x, :y

and attr_accessor does that for you.

You might want to allow some flexibility in your constructor. Your initialize method allows passing the values for x and y and will default to 10 if nothing is passed, so you can do this:

def initialize(x = 10, y = 10)
  @x = x
  @y = y
end

This way, you will get this:

p1 = Point.new 
puts p.x # => 10
puts p.y # => 10

p2 = Point.new(15, 20)
puts p.x # => 15
puts p.y # => 20

Notice how for p1 I don't pass any arguments and yet x and y both get set as expected because we are setting a default value for them in the method definition, here:

def initialize(x = 10, y = 10)

Regarding your question about why you see this:

p = Point.new
p.x = 1
p.y = 5
print p # -> #<Point:0x007f9463089cc0>

Point:0x007fa003885bf8 means that you have an instance of the class Point in your variable p . By default Ruby will call the to_s method on an object when you try to print it, since in your case you didn't define that method it will go through the inheritance chain to see who defines that method. It turns out that that method is found in the Object class which all Ruby objects implicitly inherit from, and that method's default behaviour is to print the name of the class followed by the instance's ID in memory, in the format:

#<ClassName:MemoryID>

See: http://ruby-doc.org/core-2.3.1/Object.html#method-i-to_s

If you want to change that then you can override to_s to something like this:

def to_s
  "Point #{x},#{y}"
end

That way you will get:

puts Point.new # => "Point 10,10"

There's nothing wrong.

#<Point:0x007f9463089cc0> 

simply means that it is an instance (the #<> part) of class Point with an object ID of 0x007f9463089cc0 . An object ID is an identifier for Ruby's interpreter to find each object, very much like a memory address.

Though everything is okay, there is always a way in Ruby that leads to less code. For example:

class Point
  attr_accessor :x, :y

  def initialize(x = 10, y = 10)
    @x, @y = x, y
  end
end

Or even:

Point = Struct.new(:x, :y)

Because you are declaring attr_accessor :x, :y you actually don't need to define a getter and setter for x and y , so your class can be simplified to:

class Point
  attr_accessor :x, :y
  def initialize
    @x = 10
    @y = 10
  end
end

Also you can add a to_s method to Point:

class Point
  attr_accessor :x, :y
  def initialize
    @x = 10
    @y = 10
  end

  def to_s
     "(#{x}, #{y})"
  end
end

so you can use puts p and get as ouptut (10, 10) when you do:

p = Point.new
puts p
(10, 10)  

I prefer to use puts instead of print because it insert a new-line character after the output, and it looks more readable. In to_s I'm using Ruby's string interpolation "#{}" to build a nice output for your Point instance.

Methods print and puts output the result of to_s , and p outputs the result of inspect . Unless you overwrite these methods, by default, a custom class that inherits Object returns the form #<class_name:object_id> that you got. If you want some other output, overwrite these methods, for example

class Point
  def to_s
    "#@x,#@y"
  end
end
...
print p

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM