About object-oriented inheritance and about yield Ruby

About inheritance

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[0]
y_max = ARGV[1]

if !x_max || !y_max
	puts "Please specify an argument"
	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.

About yield

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
			puts "Please specify block"
			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[0]
y_max = ARGV[1]

if !x_max || !y_max
	puts "Please specify an argument"
	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.

Recommended Posts

About object-oriented inheritance and about yield Ruby
Ruby inheritance and delegation
About encapsulation and inheritance
About Ruby hashes and symbols
About Ruby and object model
About Ruby classes and instances
About inheritance
About Ruby single quotes and double quotes
About Ruby product operator (&) and sum operator (|)
About ruby ​​form
About class inheritance.
About Ruby Hashes
About Ruby arrays
About ruby block
About Ruby Hashes
About Ruby Symbols
About Ruby variables
Ruby and Gem
Inheritance and interface.
About Ruby methods
About Ruby Kernel Module
[Ruby] I thought about the difference between each_with_index and each.with_index
About Ruby error messages
About Ruby exception handling
Symbols and Destructive Ruby
About Ruby Hashes (continued)
About eval in Ruby
[Ruby] Big Decimal and DECIMAL
About Bean and DI
[ruby] About here documents
About classes and instances
About the difference between classes and instances in Ruby
About Ruby if statement
A rough note about Ruby arrays and hash objects
About gets and gets.chomp
About Ruby instance methods
About inheritance (Java Silver)
About redirect and forward
Ruby classes and instances
Ruby variables and methods
[Ruby] About instance generation
[Technical memo] About the advantages and disadvantages of Ruby
[Ruby] Class nesting, inheritance, and the basics of self
About Serializable and serialVersionUID
Be careful about Ruby method calls and variable references
About the [ruby] operator
Thinking about logic Ruby
[Ruby] Questions and verification about the number of method arguments
About the difference between "(double quotation)" and "single quotation" in Ruby
[Ruby] About the difference between 2 dots and 3 dots of range object.
About for statement and if statement
GraphQL Ruby and actual development
Write class inheritance in Ruby
Explanation about Ruby Range object
Ruby syntax errors and countermeasures
[Ruby on Rails] about has_secure_password
About regular expressions in Ruby
[Java] About String and StringBuilder
About the same and equivalent
Summarize Ruby and Dependency Injection
Ruby About various iterative processes