It seems that it has the ability of inheritance that exists in object orientation. You can use it without writing the contents defined in the class, or you can modify the contents defined in the class to make it easier to use in the class.

merit

--Ability to create functional extensions, so-called pluggable mechanisms

Demerit

--Maintenance failure due to over-inheritance (the moment the origin is changed, problems frequently occur at the inheritance destination, etc.)

## Actually use

#### `keishou.rb`

``````
class Ball
attr_accessor :x, :y, :x_way, :y_way, :step

def initialize(x: 1, y: 1, x_way: 1, y_way: 1, step: 1)
@x = x
@y = y
@x_way = x_way
@y_way = y_way
@step = step
end

def move
@x += @x_way
@y += @y_way
@step += 1
end

def reflect_x
if @x_way == 1
@x_way = -1
elsif @x_way == -1
@x_way = 1
end
end

def reflect_y
if @y_way == 1
@y_way = -1
elsif @y_way == -1
@y_way = 1
end
end

def goal?(x_max, y_max)
@x == x_max && y == 1 \
|| @x == 1 && @y == y_max \
|| @x == 1 && @y == 1 \
|| @x == x_max && @y == y_max
end

def boundary_x?(x_max)
@x == x_max || @x == 1
end

def boundary_y?(y_max)
@y == y_max || @y == 1
end
end

class BilliardTable
attr_accessor :length_x, :length_y, :ball

def initialize(length_x: nil, length_y: nil, ball: nil)
@length_x = length_x
@length_y = length_y
@ball = ball
end

def cue
print_status

loop do
@ball.move

print_status

if @ball.goal?(@length_x, @length_y)
puts "GOAL!!"
break
elsif @ball.boundary_x?(@length_x)
@ball.reflect_x
elsif @ball.boundary_y?(@length_y)
@ball.reflect_y
end
end
end

def print_status
puts "#{@ball.step}, (#{@ball.x}, #{@ball.y})"
end
end

class MyBilliardTable < BilliardTable
def print_status
puts "step = #{@ball.step}, x = #{@ball.x}, y = #{@ball.y}"
end
end

x_max = ARGV
y_max = ARGV

if !x_max || !y_max
exit 1
end

x_max =  x_max.to_i
y_max =  y_max.to_i

(6..16).each do |times|
puts "3 x #{times}Run on the pool table"
bt = MyBilliardTable.new(length_x: 3, length_y: times, ball: Ball.new)
bt.cue
end
``````

I will continue to use the code I wrote before to inherit. In fact, the part of this code that is inherited is

#### `keishoububun.rb`

``````
class MyBilliardTable < BilliardTable
def print_status
puts "step = #{@ball.step}, x = #{@ball.x}, y = #{@ball.y}"
end
end
``````

This is the part here. You can inherit a class by specifying the parent class using the inequality sign. This time, the method of the output part is changed. Then, try to create an object using this defined class.

#### `shori.rb`

``````
(6..16).each do |times|
puts "3 x #{times}Run on the pool table"
bt = MyBilliardTable.new(length_x: 3, length_y: times, ball: Ball.new)
bt.cue
end
``````

The processing part is the above part. The output should be in a modified form, and you can see that the methods defined in the BilliardTabel class are working, although they are not defined in the MyBilliardTable class.

#### Digression

As an aside, by designing the class in an object-oriented manner, it is possible to make the BilliardTable an object, so that the board can have a pattern. This time, I'm expressing the board of 3 times x.

#### `banmen.rb`

``````
puts "3 x #{times}Run on the pool table"
``````

If you want to do solid code written in Previous article, you can do it, but it will create a double loop and loop. The more you make it, the larger the code will be, that is, the deeper the hierarchy of the code. As a result, it's hard to read and hard to fix. Just by imagining it, the code will be hard to fix and hard to read.

I think that the ease of expression and ease of writing when such conditions increase are also the advantages of object-oriented programming.

If it is a small scale, it is possible to extend the function using yield, which can be done in block units. Yield replaces the status method part as it means "replace".

#### `yield.rb`

``````
class Ball
attr_accessor :x, :y, :x_way, :y_way, :step

def initialize(x: 1, y: 1, x_way: 1, y_way: 1, step: 1)
@x = x
@y = y
@x_way = x_way
@y_way = y_way
@step = step
end

def move
@x += @x_way
@y += @y_way
@step += 1
end

def reflect_x
if @x_way == 1
@x_way = -1
elsif @x_way == -1
@x_way = 1
end
end

def reflect_y
if @y_way == 1
@y_way = -1
elsif @y_way == -1
@y_way = 1
end
end

def goal?(x_max, y_max)
@x == x_max && y == 1 \
|| @x == 1 && @y == y_max \
|| @x == 1 && @y == 1 \
|| @x == x_max && @y == y_max
end

def boundary_x?(x_max)
@x == x_max || @x == 1
end

def boundary_y?(y_max)
@y == y_max || @y == 1
end
end

class BilliardTable
attr_accessor :length_x, :length_y, :ball

def initialize(length_x: nil, length_y: nil, ball: nil)
@length_x = length_x
@length_y = length_y
@ball = ball
end

def cue
print_status

loop do
@ball.move

print_status

if @ball.goal?(@length_x, @length_y)
puts "GOAL!!"
break
elsif @ball.boundary_x?(@length_x)
@ball.reflect_x
elsif @ball.boundary_y?(@length_y)
@ball.reflect_y
end
end
end

def cue_2
if block_given?
puts "There is a block"
else
return
end

loop do
@ball.move

yield status

if @ball.goal?(@length_x, @length_y)
puts "GOAL!!"
break
elsif @ball.boundary_x?(@length_x)
@ball.reflect_x
elsif @ball.boundary_y?(@length_y)
@ball.reflect_y
end
end
end

def status
{
"step" => @ball.step,
"x" => @ball.x,
"y" => @ball.y
}
end
end

x_max = ARGV
y_max = ARGV

if !x_max || !y_max
exit 1
end

x_max =  x_max.to_i
y_max =  y_max.to_i

ball = Ball.new()

bt = BilliardTable.new(length_x: x_max, length_y: y_max, ball: ball)

#bt.cue

bt.cue_2 do |status|
puts "The number of steps is#{status["step"]}And the x coordinate is#{status["x"]}, Y coordinate#{status["y"]}is"
end
``````

Depending on the scale of the function you want to extend, it is a good idea to determine whether to use inheritance or use yield to pass blocks.