
Sebagai pelajar sains komputer, saya menghabiskan banyak masa untuk belajar dan bermain dengan bahasa baru. Setiap bahasa baru mempunyai sesuatu yang unik untuk ditawarkan. Walaupun begitu, kebanyakan pemula memulakan perjalanan pengaturcaraan mereka dengan bahasa prosedural seperti C atau dengan bahasa berorientasikan objek seperti JavaScript dan C ++.
Oleh itu, masuk akal untuk mempelajari asas-asas pengaturcaraan berorientasikan objek sehingga anda dapat memahami konsep dan menerapkannya pada bahasa yang anda pelajari dengan mudah. Kami akan menggunakan bahasa pengaturcaraan Ruby sebagai contoh.
Anda mungkin bertanya, mengapa Ruby? Kerana ia "dirancang untuk membuat pengaturcara bahagia" dan juga kerana hampir semua perkara di Ruby adalah objek.
Mengetahui Paradigma Berorientasikan Objek (OOP)
Dalam OOP, kami mengenal pasti "perkara" yang dikendalikan oleh program kami. Sebagai manusia, kita memikirkan perkara sebagai objek dengan atribut dan tingkah laku, dan kita berinteraksi dengan perkara berdasarkan sifat dan tingkah laku ini. Satu perkara boleh menjadi kereta, buku dan sebagainya. Perkara semacam itu menjadi kelas (cetak biru objek), dan kami membuat objek dari kelas ini.
Setiap kejadian (objek) mengandungi pemboleh ubah contoh yang merupakan keadaan objek (atribut). Tingkah laku objek dilambangkan dengan kaedah.
Mari kita ambil contoh kereta. Kereta adalah perkara yang menjadikannya kelas . Jenis kereta tertentu, katakan BMW adalah objek kereta kelas . Yang sifat-sifat / ciri-ciri sebuah BMW seperti bilangan warna dan model yang boleh disimpan dalam pembolehubah misalnya. Dan jika anda ingin melakukan operasi objek, seperti memandu, maka "drive" menggambarkan tingkah laku yang didefinisikan sebagai kaedah .
Pelajaran Sintaksis Pantas
- Untuk mengakhiri garis dalam program Ruby, titik koma (;) adalah pilihan (tetapi umumnya tidak digunakan)
- Indentasi 2-ruang untuk setiap tingkat bersarang digalakkan (tidak diperlukan, seperti di Python)
- Tidak ada pendakap keriting
{}
yang digunakan, dan kata kunci akhir digunakan untuk menandakan akhir blok kawalan aliran - Untuk memberi komen, kami menggunakan
#
simbol
Cara objek dibuat di Ruby adalah dengan memanggil kaedah baru di kelas, seperti dalam contoh di bawah:
class Car def initialize(name, color) @name = name @color = color end
def get_info "Name: #{@name}, and Color: #{@color}" endend
my_car = Car.new("Fiat", "Red")puts my_car.get_info
Untuk memahami apa yang berlaku dalam kod di atas:
- Kami mempunyai kelas yang dinamakan
Car
dengan dua kaedah,initialize
danget_info
. - Pemboleh ubah contoh dalam Ruby bermula dengan
@
(Contohnya@name
). Bahagian yang menarik adalah bahawa pemboleh ubah tidak dinyatakan pada mulanya. Mereka muncul ketika mula-mula digunakan, dan setelah itu mereka tersedia untuk semua kaedah contoh kelas. - Memanggil
new
kaedah menyebabkaninitialize
kaedah memanggil.initialize
adalah kaedah khas yang digunakan sebagai konstruktor.
Mengakses Data
Pemboleh ubah contoh adalah peribadi dan tidak dapat diakses dari luar kelas. Untuk mengaksesnya, kita perlu membuat kaedah. Kaedah contoh mempunyai akses awam secara lalai. Kita boleh menghadkan akses ke kaedah contoh ini seperti yang akan kita lihat nanti dalam artikel ini.
Untuk mendapatkan dan mengubah data, masing-masing kita memerlukan metode "getter" dan "setter". Mari lihat kaedah ini dengan mengambil contoh kereta yang sama.
class Car def initialize(name, color) # "Constructor" @name = name @color = color end
def color @color end
def color= (new_color) @color = new_color endend
my_car = Car.new("Fiat", "Red")puts my_car.color # Red
my_car.color = "White"puts my_car.color # White
Dalam Ruby, "getter" dan "setter" didefinisikan dengan nama yang sama dengan pemboleh ubah instance yang kita hadapi.
Dalam contoh di atas, apabila kita katakan my_car.color
, sebenarnya memanggil color
kaedah yang seterusnya mengembalikan nama warnanya.
Catatan: Perhatikan bagaimana Ruby membenarkan ruang antara color
dan sama untuk menandatangani semasa menggunakan setter, walaupun nama kaedahnya adalahcolor=
Menulis kaedah getter / setter ini membolehkan kita mempunyai lebih banyak kawalan. Tetapi selalunya, mendapatkan nilai yang ada dan menetapkan nilai baru adalah mudah. Jadi, harus ada cara yang lebih mudah daripada sebenarnya menentukan kaedah getter / setter.
Cara yang lebih mudah
Dengan menggunakan attr_*
borang sebagai gantinya, kita dapat memperoleh nilai yang ada dan menetapkan nilai baru.
attr_accessor
: untuk getter dan setter kedua-duanyaattr_reader
: untuk mendapatkan sahajaattr_writer
: untuk setter sahaja
Mari lihat borang ini dengan contoh kereta yang sama.
class Car attr_accessor :name, :colorend
car1 = Car.newputs car1.name # => nil
car1.name = "Suzuki"car1.color = "Gray"puts car1.color # => Gray
car1.name = "Fiat"puts car1.name # => Fiat
Dengan cara ini kita boleh melangkau definisi getter / setter sama sekali.
Bercakap mengenai amalan terbaik
Dalam contoh di atas, kami tidak menginisialisasi nilai untuk pemboleh ubah @name
dan @color
contoh, yang bukan merupakan amalan yang baik. Juga, kerana pemboleh ubah contoh diatur ke nihil, objek car1
tersebut tidak masuk akal. Menjadi amalan yang baik untuk menetapkan pemboleh ubah contoh menggunakan konstruktor seperti contoh di bawah.
class Car attr_accessor :name, :color def initialize(name, color) @name = name @color = color endend
car1 = Car.new("Suzuki", "Gray")puts car1.color # => Gray
car1.name = "Fiat"puts car1.name # => Fiat
Kaedah Kelas dan Pemboleh ubah Kelas
Oleh itu kaedah kelas digunakan pada kelas, bukan pada contoh kelas. Ini serupa dengan kaedah statik di Jawa.
Catatan: self
di luar definisi kaedah merujuk kepada objek kelas. Pemboleh ubah kelas bermula dengan@@
Sekarang, sebenarnya ada tiga cara untuk menentukan kaedah kelas dalam Ruby:
Di dalam definisi kelas
- Menggunakan kata kunci sendiri dengan nama kaedah:
class MathFunctions def self.two_times(num) num * 2 endend
# No instance createdputs MathFunctions.two_times(10) # => 20
2. Menggunakan <<
; diri
class MathFunctions class << self def two_times(num) num * 2 end endend
# No instance createdputs MathFunctions.two_times(10) # => 20
Di luar definisi kelas
3. Using class name with the method name
class MathFunctionsend
def MathFunctions.two_times(num) num * 2end
# No instance createdputs MathFunctions.two_times(10) # => 20
Class Inheritance
In Ruby, every class implicitly inherits from the Object class. Let’s look at an example.
class Car def to_s "Car" end
def speed "Top speed 100" endend
class SuperCar < Car def speed # Override "Top speed 200" endend
car = Car.newfast_car = SuperCar.new
puts "#{car}1 #{car.speed}" # => Car1 Top speed 100puts "#{fast_car}2 #{fast_car.speed}" # => Car2 Top speed 200
In the above example, the SuperCar
class overrides the speed
method which is inherited from the Car
class. The symbol &
lt; denotes inheritance.
Note: Ruby doesn’t support multiple inheritance, and so mix-ins are used instead. We will discuss them later in this article.
Modules in Ruby
A Ruby module is an important part of the Ruby programming language. It’s a major object-oriented feature of the language and supports multiple inheritance indirectly.
A module is a container for classes, methods, constants, or even other modules. Like a class, a module cannot be instantiated, but serves two main purposes:
- Namespace
- Mix-in
Modules as Namespace
A lot of languages like Java have the idea of the package structure, just to avoid collision between two classes. Let’s look into an example to understand how it works.
module Patterns class Match attr_accessor :matched endend
module Sports class Match attr_accessor :score endend
match1 = Patterns::Match.newmatch1.matched = "true"
match2 = Sports::Match.newmatch2.score = 210
In the example above, as we have two classes named Match
, we can differentiate between them and prevent collision by simply encapsulating them into different modules.
Modules as Mix-in
In the object-oriented paradigm, we have the concept of Interfaces. Mix-in provides a way to share code between multiple classes. Not only that, we can also include the built-in modules like Enumerable
and make our task much easier. Let’s see an example.
module PrintName attr_accessor :name def print_it puts "Name: #{@name}" endend
class Person include PrintNameend
class Organization include PrintNameend
person = Person.newperson.name = "Nishant"puts person.print_it # => Name: Nishant
organization = Organization.neworganization.name = "freeCodeCamp"puts organization.print_it # => Name: freeCodeCamp
Mix-ins are extremely powerful, as we only write the code once and can then include them anywhere as required.
Scope in Ruby
We will see how scope works for:
- variables
- constants
- blocks
Scope of variables
Methods and classes define a new scope for variables, and outer scope variables are not carried over to the inner scope. Let’s see what this means.
name = "Nishant"
class MyClass def my_fun name = "John" puts name # => John end
puts name # => Nishant
The outer name
variable and the inner name
variable are not the same. The outer name
variable doesn’t get carried over to the inner scope. That means if you try to print it in the inner scope without again defining it, an exception would be thrown — no such variable exists
Scope of constants
An inner scope can see constants defined in the outer scope and can also override the outer constants. But it’s important to remember that even after overriding the constant value in the inner scope, the value in the outer scope remains unchanged. Let’s see it in action.
module MyModule PI = 3.14 class MyClass def value_of_pi puts PI # => 3.14 PI = "3.144444" puts PI # => 3.144444 end end puts PI # => 3.14end
Scope of blocks
Blocks inherit the outer scope. Let’s understand it using a fantastic example I found on the internet.
class BankAccount attr_accessor :id, :amount def initialize(id, amount) @id = id @amount = amount endend
acct1 = BankAccount.new(213, 300)acct2 = BankAccount.new(22, 100)acct3 = BankAccount.new(222, 500)
accts = [acct1, acct2, acct3]
total_sum = 0accts.each do |eachAcct| total_sum = total_sum + eachAcct.amountend
puts total_sum # => 900
In the above example, if we use a method to calculate the total_sum
, the total_sum
variable would be a totally different variable inside the method. That’s why sometimes using blocks can save us a lot of time.
Having said that, a variable created inside the block is only available to the block.
Access Control
When designing a class, it is important to think about how much of it you’ll be exposing to the world. This is known as Encapsulation, and typically means hiding the internal representation of the object.
There are three levels of access control in Ruby:
- Public - no access control is enforced. Anybody can call these methods.
- Protected - can be invoked by objects of the defining classes or its sub classes.
- Private - cannot be invoked except with an explicit receiver.
Let’s see an example of Encapsulation in action:
class Car def initialize(speed, fuel_eco) @rating = speed * comfort end
def rating @rating endend
puts Car.new(100, 5).rating # => 500
Now, as the details of how the rating is calculated are kept inside the class, we can change it at any point in time without any other change. Also, we cannot set the rating from outside.
Talking about the ways to specify access control, there are two of them:
- Specifying public, protected, or private and everything until the next access control keyword will have that access control level.
- Define the method regularly, and then specify public, private, and protected access levels and list the comma(,) separated methods under those levels using method symbols.
Example of the first way:
class MyClass private def func1 "private" end protected def func2 "protected" end public def func3 "Public" endend
Example of the second way:
class MyClass def func1 "private" end def func2 "protected" end def func3 "Public" end private :func1 protected :func2 public :func3end
Note: The public and private access controls are used the most.
Conclusion
These are the very basics of Object Oriented Programming in Ruby. Now, knowing these concepts you can go deeper and learn them by building cool stuff.
Don’t forget to clap and follow if you enjoyed! Keep up with me here.