Wie man Code schreibt, der objektorientiertes Ruby denkt

Was ist objektorientiert?

Es ist eine Entwurfsmethode, keine Grammatik. Als ich es zum ersten Mal hörte, dachte ich, es sei eine Art Grammatik oder Syntax, aber das ist nicht der Fall. Es scheint, dass das richtige Verständnis darin besteht, dass Ruby eine Syntax hat, die leicht in Übereinstimmung mit der Objektorientierung zu schreiben ist.

Warum objektorientiert schreiben?

Ich denke, da ist etwas drin. Dieses Mal werde ich mich auf diesen Punkt konzentrieren und ihn zusammenfassen.

Versuchen Sie zunächst zu schreiben, ohne über die Objektorientierung nachzudenken

toriaezuugoku.rb


x_max = ARGV[0]
y_max = ARGV[1]

if !x_max || !y_max
  puts "Bitte geben Sie das Argument an"
  exit 1
end

x_max =  x_max.to_i
y_max =  y_max.to_i

#Status
x = 1
y = 1
step = 1
x_way = 1
y_way = 1

puts " #{step} (#{x},#{y})"
x += 1
y += 1
loop do
  step += 1
  puts " #{step} (#{x},#{y})"

  if y == 1 && x == x_max || x == 1 && y == y_max || x == 1 && y == 1 || x == x_max && y == y_max
    puts "GOAL!!"
    break
  elsif x == x_max
    x_way = -1
  elsif y == y_max
    y_way = -1
  elsif x == 1
    x_way = 1
  elsif y == 1
    y_way = 1
  end

  x += x_way
  y += y_way
end

Dies ist der Code, den ich im vorherigen Artikel geschrieben habe. Es ist so geschrieben, dass die gesamte Verarbeitung von oben nach unten verläuft, ohne eine Funktion zu definieren. Dies ist der am schwersten zu lesende Code. Dies liegt daran, dass die Spezifikationen so sind, dass die Funktion nur gelesen werden kann, wenn nach der eigentlichen Verarbeitung anhand der Definition der Variablen vorhergesagt wird, was getan wird. Lassen Sie uns aufgeben, zu lesen, was dieser Code im Laufe der Zeit hier tut, und als nächstes den umgeschriebenen Code betrachten.

methodtohash.rb


def move_ball(hash)
	hash["x"] += hash["x_way"]
	hash["y"] += hash["y_way"]
	hash["step"] += 1
end

def reflect_x(hash)
	if hash["x_way"] == 1
		hash["x_way"] = -1
  elsif hash["x_way"] == -1
    hash["x_way"] = 1
  end
end

def reflect_y(hash)
	if hash["y_way"] == 1
		hash["y_way"] = -1
  elsif hash["y_way"] == -1
    hash["y_way"] = 1
  end
end

def goal?(hash, x_max, y_max)
  hash["y"] == 1 && hash["x"] == x_max \
  || hash["x"] == 1 && hash["y"] == y_max \
  || hash["x"] == 1 && hash["y"] == 1 \
  || hash["x"] == x_max && hash["y"] == y_max
end

def boundary_x?(hash, x_max)
  hash["x"] == x_max || hash["x"] == 1
end

def boundary_y?(hash, y_max)
  hash["y"] == y_max || hash["y"] == 1
end

x_max = ARGV[0]
y_max = ARGV[1]

if !x_max || !y_max
  puts "Bitte geben Sie das Argument an"
  exit 1
end

x_max =  x_max.to_i
y_max =  y_max.to_i

state = {
  "x" => 1,
  "y" => 1,
  "step" => 1,
  "x_way" => 1,
  "y_way" => 1
}

puts " #{state["step"]} (#{state["x"]},#{state["y"]})"

loop do
  move_ball(state)

  puts " #{state["step"]} (#{state["x"]},#{state["y"]})"

  if goal?(state, x_max, y_max)
    puts "GOAL!!"
    break
  elsif boundary_x?(state, x_max)
    reflect_x(state)
  elsif boundary_y?(state, y_max)
    reflect_y(state)
  end
end

Dieses Mal habe ich es mit der Funktionsdefinition und dem Hash geschrieben. Wenn man sich die Schleifenanweisung ansieht, scheint es, dass der Status des Inhalts des Hashs, der als Status bezeichnet wird, durch die Methode namens move_ball und x und y manipuliert wird, wenn der Ball im bedingten Ausdruck mit border_x und border_y springt. Ich frage mich, ob die Koordinaten durch Reflect_x und Reflect_y geändert werden ... Es wird zu etwas, das nicht gelesen werden kann. Wenn die Verarbeitung der durch die Funktion definierten Inhalte korrekt ist, kann der Leser leicht verstehen, was er tut und was dieser Code tut, indem er nur hier liest. Es gibt einen solchen Vorteil, wenn Sie den Teil, in dem der Status geändert wird, in Funktionen aufteilen. Die Verwendung von Hashes macht die Statusverwaltung sicherer als im vorherigen Code, der mit vielen globalen Variablen dargestellt wurde, und ist mit zunehmender Anzahl von Bällen immer noch etwas flexibler. (Wenn die Anzahl der Bälle unangemessen groß oder unbekannt ist, können wir damit nicht umgehen.) Es reicht jedoch immer noch nicht aus, um die Lesbarkeit zu gewährleisten. Wenn Sie einen Fehler wie einen Hash machen, gibt dieser Code nur null zurück, wodurch es schwieriger wird, den Fehler zu erkennen. Je größer das Produkt, desto schwieriger ist es zu entdecken.

Es ist also eine objektorientierte Wendung.

object.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

x_max = ARGV[0]
y_max = ARGV[1]

if !x_max || !y_max
	puts "Bitte geben Sie das Argument an"
	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

Sie können wie oben schreiben. Teilen Sie den Zustand des Balls und den Zustand des Billardtisches in Klassen ein, definieren Sie die Zustandsoperationsmethode, die für die Funktion des Balls in der Ballklasse erforderlich ist, und definieren Sie die Verarbeitung des Vorgangs auf dem Tisch, der den Ball in der Billardklasse bewegt hat. Wenn Sie also das allgemeine Verhalten dieses Codes kennen möchten, können Sie es erfassen, indem Sie das Verarbeitungssystem der Billardklasse und den Teil lesen, der das Befehlszeilenargument empfängt, dh den außerhalb der Klasse geschriebenen Codeteil. Ich kann. Die englische Namenskonvention ist auch viel einfacher zu lesen. Wenn Sie schließlich Cue (Poke) gegen BT (Billardstand) ausführen, bewegt sich der Ball. Sehr leicht zu lesen. Da die Statusoperationen sehr detailliert definiert sind, haben sich meiner Meinung nach auch die Benutzerfreundlichkeit des Codes und die Aufrufbarkeit der Methode verbessert. Ich denke, dies macht die Fehlerbehebung einfacher als die beiden zuvor erwähnten festen Codes und Hash-Codes.

Zusammenfassung

Ich habe versucht, den zweistufigen Code aus dem soliden Schreibprozess, den ich zuerst geschrieben habe, neu zu schreiben, aber ich habe verstanden, wie schwierig es ist, den Code zu lesen, den ich zuerst geschrieben habe, sozusagen, es ist schmutziger Code. .. Ich habe viel Code-Verarbeitung geschrieben, wie die erste, die ich in Rails geschrieben habe. Dies ist ein Framework, das das Klassendesign durch Objektorientierung vereinfacht, also habe ich Yabe-Code erstellt. War noch prominenter und gut verstanden.

Recommended Posts

Wie man Code schreibt, der objektorientiertes Ruby denkt
Wie man guten Code schreibt
So schreiben Sie leicht verständlichen Code [Zusammenfassung 3]
Schreiben Sie Code, der schwer zu testen ist
Wie schreibe ich Rails
Schreiben Sie einfach zu wartenden Code (Teil 1)
Wie schreibe ich Docker-Compose
Wie schreibe ich Mockito
Schreiben Sie einfach zu pflegenden Code (Teil 4)
So schreiben Sie Testcode mit Basic-Zertifizierung
So schreiben Sie eine Migrationsdatei
Schreiben Sie einfach zu wartenden Code (Teil 3)
[Ruby on Rails] Wie schreibe ich eine Enumeration auf Japanisch?
Verwendung von Ruby return
Wie schreibe ich einen Java-Kommentar
Ruby: Wie man Cookies benutzt
Wie schreibe ich Junit 5 organisiert
Wie schreibe ich Rails Seed
Wie schreibe ich Rails Routing
Vergleich des Schreibens von Callback-Funktionen (Java, JavaScript, Ruby)
Java 14 neue Funktionen, mit denen Code geschrieben werden kann
Wie man in Ruby auf unbestimmte Zeit iteriert
Java # 6 studieren (Wie man Blöcke schreibt)
So installieren Sie Ruby über rbenv
So installieren Sie Bootstrap in Ruby
[Rails] Wie schreibe ich eine Ausnahmebehandlung?
So schreiben Sie eine Java-Variablendeklaration
Verwendung der Ruby-Inject-Methode
Wie man Ruby's irb ausführt (interaktiver Ruby)
Ich habe versucht, Code wie eine Typdeklaration in Ruby zu schreiben
[R Spec on Rails] So schreiben Sie Testcode für Anfänger von Anfängern
Offline-Echtzeit zum Schreiben eines F03-Ruby- und C-Implementierungsbeispiels
Wie schreibe ich Ruby, wenn in einer Zeile Zusammenfassung vom Anfänger
Schreiben wir einen Code, der einfach zu pflegen ist (Teil 2)
[Basic] So schreiben Sie ein Dockerfile Selbstlernend ②
[Einführung in Java] So schreiben Sie ein Java-Programm
So rufen Sie Swift 5.3-Code von Objective-C auf
Rubinlänge, -größe, -anzahl Verwendung
[Java] Wie man Dateien ausgibt und schreibt!
[Ruby] Wie man Slice für Anfänger benutzt
[Ruby on Rails] Verwendung von redirect_to
[Einfach] So aktualisieren Sie Ruby und Bundler
Schreiben Sie Code mit Ruby-Klassen und -Instanzen
So schreiben Sie den Spring AOP Point Cut Specifier
Ruby: CSV :: Verwendung von Table Note