- GUI
- Windows API tutorial
- Introduction to Windows API
- Windows API main functions
- System functions in Windows API
- Strings in Windows API
- Date & time in Windows API
- A window in Windows API
- First steps in UI
- Windows API menus
- Windows API dialogs
- Windows API controls I
- Windows API controls II
- Windows API controls III
- Advanced controls in Windows API
- Custom controls in Windows API
- The GDI in Windows API
- PyQt4 tutorial
- PyQt5 tutorial
- Qt4 tutorial
- Introduction to Qt4 toolkit
- Qt4 utility classes
- Strings in Qt4
- Date and time in Qt4
- Working with files and directories in Qt4
- First programs in Qt4
- Menus and toolbars in Qt4
- Layout management in Qt4
- Events and signals in Qt4
- Qt4 Widgets
- Qt4 Widgets II
- Painting in Qt4
- Custom widget in Qt4
- The Breakout game in Qt4
- Qt5 tutorial
- Introduction to Qt5 toolkit
- Strings in Qt5
- Date and time in Qt5
- Containers in Qt5
- Working with files and directories in Qt5
- First programs in Qt5
- Menus and toolbars in Qt5
- Layout management in Qt5
- Events and signals in Qt5
- Qt5 Widgets
- Qt5 Widgets II
- Painting in Qt5
- Custom widget in Qt5
- Snake in Qt5
- The Breakout game in Qt5
- PySide tutorial
- Tkinter tutorial
- Tcl/Tk tutorial
- Qt Quick tutorial
- Java Swing tutorial
- JavaFX tutorial
- Java SWT tutorial
- wxWidgets tutorial
- Introduction to wxWidgets
- wxWidgets helper classes
- First programs in wxWidgets
- Menus and toolbars in wxWidgets
- Layout management in wxWidgets
- Events in wxWidgets
- Dialogs in wxWidgets
- wxWidgets widgets
- wxWidgets widgets II
- Drag and Drop in wxWidgets
- Device Contexts in wxWidgets
- Custom widgets in wxWidgets
- The Tetris game in wxWidgets
- wxPython tutorial
- Introduction to wxPython
- First Steps
- Menus and toolbars
- Layout management in wxPython
- Events in wxPython
- wxPython dialogs
- Widgets
- Advanced widgets in wxPython
- Drag and drop in wxPython
- Internationalisation
- Application skeletons in wxPython
- The GDI
- Mapping modes
- Creating custom widgets
- Tips and Tricks
- wxPython Gripts
- The Tetris game in wxPython
- C# Winforms Mono tutorial
- Java Gnome tutorial
- Introduction to Java Gnome
- First steps in Java Gnome
- Layout management in Java Gnome
- Layout management II in Java Gnome
- Menus in Java Gnome
- Toolbars in Java Gnome
- Events in Java Gnome
- Widgets in Java Gnome
- Widgets II in Java Gnome
- Advanced widgets in Java Gnome
- Dialogs in Java Gnome
- Pango in Java Gnome
- Drawing with Cairo in Java Gnome
- Drawing with Cairo II
- Nibbles in Java Gnome
- QtJambi tutorial
- GTK+ tutorial
- Ruby GTK tutorial
- GTK# tutorial
- Visual Basic GTK# tutorial
- PyGTK tutorial
- Introduction to PyGTK
- First steps in PyGTK
- Layout management in PyGTK
- Menus in PyGTK
- Toolbars in PyGTK
- Signals & events in PyGTK
- Widgets in PyGTK
- Widgets II in PyGTK
- Advanced widgets in PyGTK
- Dialogs in PyGTK
- Pango
- Pango II
- Drawing with Cairo in PyGTK
- Drawing with Cairo II
- Snake game in PyGTK
- Custom widget in PyGTK
- PHP GTK tutorial
- C# Qyoto tutorial
- Ruby Qt tutorial
- Visual Basic Qyoto tutorial
- Mono IronPython Winforms tutorial
- Introduction
- First steps in IronPython Mono Winforms
- Layout management
- Menus and toolbars
- Basic Controls in Mono Winforms
- Basic Controls II in Mono Winforms
- Advanced Controls in Mono Winforms
- Dialogs
- Drag & drop in Mono Winforms
- Painting
- Painting II in IronPython Mono Winforms
- Snake in IronPython Mono Winforms
- The Tetris game in IronPython Mono Winforms
- FreeBASIC GTK tutorial
- Jython Swing tutorial
- JRuby Swing tutorial
- Visual Basic Winforms tutorial
- JavaScript GTK tutorial
- Ruby HTTPClient tutorial
- Ruby Faraday tutorial
- Ruby Net::HTTP tutorial
- Java 2D games tutorial
- Java 2D tutorial
- Cairo graphics tutorial
- PyCairo tutorial
- HTML5 canvas tutorial
- Python tutorial
- Python language
- Interactive Python
- Python lexical structure
- Python data types
- Strings in Python
- Python lists
- Python dictionaries
- Python operators
- Keywords in Python
- Functions in Python
- Files in Python
- Object-oriented programming in Python
- Modules
- Packages in Python
- Exceptions in Python
- Iterators and Generators
- Introspection in Python
- Ruby tutorial
- PHP tutorial
- Visual Basic tutorial
- Visual Basic
- Visual Basic lexical structure
- Basics
- Visual Basic data types
- Strings in Visual Basic
- Operators
- Flow control
- Visual Basic arrays
- Procedures & functions in Visual Basic
- Organizing code in Visual Basic
- Object-oriented programming
- Object-oriented programming II in Visual Basic
- Collections in Visual Basic
- Input & output
- Tcl tutorial
- C# tutorial
- Java tutorial
- AWK tutorial
- Jetty tutorial
- Tomcat Derby tutorial
- Jtwig tutorial
- Android tutorial
- Introduction to Android development
- First Android application
- Android Button widgets
- Android Intents
- Layout management in Android
- Android Spinner widget
- SeekBar widget
- Android ProgressBar widget
- Android ListView widget
- Android Pickers
- Android menus
- Dialogs
- Drawing in Android
- Java EE 5 tutorials
- Introduction
- Installing Java
- Installing NetBeans 6
- Java Application Servers
- Resin CGIServlet
- JavaServer Pages, (JSPs)
- Implicit objects in JSPs
- Shopping cart
- JSP & MySQL Database
- Java Servlets
- Sending email in a Servlet
- Creating a captcha in a Servlet
- DataSource & DriverManager
- Java Beans
- Custom JSP tags
- Object relational mapping with iBATIS
- Jsoup tutorial
- MySQL tutorial
- MySQL quick tutorial
- MySQL storage engines
- MySQL data types
- Creating, altering and dropping tables in MySQL
- MySQL expressions
- Inserting, updating, and deleting data in MySQL
- The SELECT statement in MySQL
- MySQL subqueries
- MySQL constraints
- Exporting and importing data in MySQL
- Joining tables in MySQL
- MySQL functions
- Views in MySQL
- Transactions in MySQL
- MySQL stored routines
- MySQL Python tutorial
- MySQL Perl tutorial
- MySQL C API programming tutorial
- MySQL Visual Basic tutorial
- MySQL PHP tutorial
- MySQL Java tutorial
- MySQL Ruby tutorial
- MySQL C# tutorial
- SQLite tutorial
- SQLite C tutorial
- SQLite PHP tutorial
- SQLite Python tutorial
- SQLite Perl tutorial
- SQLite Ruby tutorial
- SQLite C# tutorial
- SQLite Visual Basic tutorial
- PostgreSQL C tutorial
- PostgreSQL Python tutorial
- PostgreSQL Ruby tutorial
- PostgreSQL PHP tutorial
- PostgreSQL Java tutorial
- Apache Derby tutorial
- SQLAlchemy tutorial
- MongoDB PHP tutorial
- MongoDB Java tutorial
- MongoDB JavaScript tutorial
- MongoDB Ruby tutorial
- Spring JdbcTemplate tutorial
- JDBI tutorial
Object-oriented programming in Ruby
In this part of the Ruby tutorial, we will talk about object-oriented programming in Ruby.
Programming languages have procedural programming, functional programming and object-oriented programming paradigms. Ruby is an object-oriented language with some functional and procedural features.
Object-oriented programming (OOP) is a programming paradigm that uses objects and their interactions to design applications and computer programs.
The basic programming concepts in OOP are:
- Abstraction
- Polymorphism
- Encapsulation
- Inheritance
The abstraction is simplifying complex reality by modeling classes appropriate to the problem. The polymorphism is the process of using an operator or function in different ways for different data input. The encapsulation hides the implementation details of a class from other objects. The inheritance is a way to form new classes using classes that have already been defined.
Objects
Objects are basic building blocks of a Ruby OOP program. An object is a combination of data and methods. In a OOP program, we create objects. These objects communicate together through methods. Each object can receive messages, send messages and process data.
There are two steps in creating an object. First, we define a class. A class is a template for an object. It is a blueprint that describes the state and behavior that the objects of the class all share. A class can be used to create many objects. Objects created at runtime from a class are called instances of that particular class.
#!/usr/bin/ruby class Being end b = Being.new puts b
In our first example, we create a simple object.
class Being end
This is a simple class definition. The body of the template is empty. It does not have any data or methods.
b = Being.new
We create a new instance of the Being class. For this we have the new
method. The b variable stores the newly created object.
puts b
We print the object to the console to get some basic description of the object. When we print an object, we in fact call its to_s
method. But we have not defined any method yet. It is because every object created inherits from the base Object
. It has some elementary functionality, which is shared among all objects created. One of this is the to_s
method.
$ ./simple.rb #<Being:0x9f3c290>
We get the object class name.
The constructor
A constructor is a special kind of a method. It is automatically called when an object is created. Constructors do not return values. The purpose of the constructor is to initiate the state of an object. The constructor in Ruby is called initialize
. Constructors do not return any values.
Constructors cannot be inherited. The constructor of a parent object is called with a super
method. They are called in the order of inheritance.
#!/usr/bin/ruby class Being def initialize puts "Being is created" end end Being.new
We have a Being class.
class Being def initialize puts "Being is created" end end
The Being class has a constructor method called initialize
. It prints a message to the console. The definition of a Ruby method is placed between the def
and end
keywords.
Being.new
An instance of the Being
class is created. At the moment of the object creation, the constructor method is called.
$ ./constructor.rb Being is created
This is the output of the program.
An object's attributes are the data items that are bundled inside that object. These items are also called instance variables or member fields. An instance variable is a variable defined in a class, for which each object in the class has a separate copy.
In the next example, we initiate data members of the class. Initiation of variables is a typical job for constructors.
#!/usr/bin/ruby class Person def initialize name @name = name end def get_name @name end end p1 = Person.new "Jane" p2 = Person.new "Beky" puts p1.get_name puts p2.get_name
In the above Ruby code, we have a Person
class with one member field.
class Person def initialize name @name = name end
In the constructor of the Person class, we set a member field to a value name. The name parameter is passed to the constructor at creation. A constructor is a method called initialize
that is being called at the creation of an instance object. The @name
is an instance variable. Instance variables start with @
character in Ruby.
def get_name @name end
The get_name
method returns the member field. In Ruby member fields are accessible only via methods.
p1 = Person.new "Jane" p2 = Person.new "Beky"
We create two objects of a Person
class. A string parameter is passed to each object constructor. The names are stored inside instance variables that are unique to each object.
puts p1.get_name puts p2.get_name
We print the member fields by calling the get_name
on each of the objects.
$ ./person.rb Jane Beky
We see the output of the program. Each instance of the Person
class has its own name member field.
We can create an object without calling the constructor. Ruby has a special allocate
method for this. The allocate
method allocates space for a new object of a class and does not call initialize on the new instance.
#!/usr/bin/ruby class Being def initialize puts "Being created" end end b1 = Being.new b2 = Being.allocate puts b2
In the example, we create two objects. The first object using the new
method, the second object using the allocate
method.
b1 = Being.new
Here we create an instance of the object with the new
keyword. The constructor method initialize
is called and the message is printed to the console.
b2 = Being.allocate puts b2
In case of the allocate
method, the constructor is not called. We call the to_s
method with the puts
keyword to show that the object was created.
$ ./allocate.rb Being created #<Being:0x8ea0044>
Here we see the output of the program.
Constructor overloading
Constructor overloading is the ability to have multiple types of constructors in a class. This way we can create an object with different number or different types of parameters.
Ruby has no constructor overloading that we know from some programming languages. This behaviour can be simulated to some extent with default parameter values in Ruby.
#!/usr/bin/ruby class Person def initialize name="unknown", age=0 @name = name @age = age end def to_s "Name: #{@name}, Age: #{@age}" end end p1 = Person.new p2 = Person.new "unknown", 17 p3 = Person.new "Becky", 19 p4 = Person.new "Robert" p p1, p2, p3, p4
This example shows how we could simulate constructor overloading on a Person
class that has two member fields. When the name parameter is not specified, the string "unknown" is used instead. For unspecified age we have 0.
def initialize name="unknown", age=0 @name = name @age = age end
The constructor takes two parameters. They have a default value. The default value is used if we do not specify our own values at the object creation. Note that the order of parameters must be kept. First comes the name, then the age.
p1 = Person.new p2 = Person.new "unknown", 17 p3 = Person.new "Becky", 19 p4 = Person.new "Robert" p p1, p2, p3, p4
We create four objects. The constructors take different number of parameters.
$ ./consover.rb Name: unknown, Age: 0 Name: unknown, Age: 17 Name: Becky, Age: 19 Name: Robert, Age: 0
This is the output of the example.
Methods
Methods are functions defined inside the body of a class. They are used to perform operations with the attributes of our objects. Methods are essential in the encapsulation concept of the OOP paradigm. For example, we might have a connect method in our AccessDatabase
class. We need not to be informed how exactly the method connects to the database. We only have to know that it is used to connect to a database. This is essential in dividing responsibilities in programming, especially in large applications.
In Ruby, data is accessible only via methods.
#!/usr/bin/ruby class Person def initialize name @name = name end def get_name @name end end per = Person.new "Jane" puts per.get_name puts per.send :get_name
The example shows two basic ways to call a method.
puts per.get_name
The common way is to use a dot operator on an object followed by a method name.
puts per.send :get_name
The alternative is to use a built-in send
method. It takes a symbol of the method to be called as a parameter.
Methods typically perform some action on an object's data.
#!/usr/bin/ruby class Circle @@PI = 3.141592 def initialize @radius = 0 end def set_radius radius @radius = radius end def area @radius * @radius * @@PI end end c = Circle.new c.set_radius 5 puts c.area
In the code example, we have a Circle class. We define two methods.
@@PI = 3.141592
We have defined a @@PI
variable in our Circle
class. It is a class variable. Class variables start with @@
sigils in Ruby. Class variables belong to a class, not to an object. Each object has access to its class variables. We use the @@PI
to compute the area of the circle.
def initialize @radius = 0 end
We have one member field. It is the radius of the circle. If we want to modify this variable from the outside, we must use the publicly available set_radius
method. The data is protected.
def set_radius radius @radius = radius end
This is the set_radius
method. It gives the @radius
instance variable a new value.
def area @radius * @radius * @@PI end
The area method returns the area of a circle. This is a typical task for a method. It works with data and produces some value for us.
c = Circle.new c.set_radius 5 puts c.area
We create an instance of the Circle class, and set its radius by calling the set_radius
method on the object of the circle. We use the dot operator to call the method.
$ ./circle.rb 78.5398
Running the example we get this output.
Access modifiers
Access modifiers set the visibility of methods and member fields. Ruby has three access modifiers: public
, protected
and private
. In Ruby, all data members are private. Access modifiers can be used only on methods. Ruby methods are public, unless we say otherwise.
The public
methods can be accessed from inside the definition of the class as well as from the outside of the class. The difference between the protected
and the private
methods is subtle. Neither can be accessed outside the definition of the class. They can be accessed only within the class itself and by inherited or parent classes.
Note that unlike in other object-oriented programming languages, inheritance does not play role in Ruby access modifiers. Only two things are important. First, if we call the method inside or outside the class definition. Second, if we use or do not use the self
keyword which points to the current receiver.
Access modifiers protect data against accidental modifications. They make the programs more robust. The implementation of some methods is subject to change. These methods are good candidates for being private. The interface that is made public to the users should only change when really necessary. Over the years users are accustomed to using specific methods and breaking backward compatibility is generally frowned upon.
#!/usr/bin/ruby class Some def method1 puts "public method1 called" end public def method2 puts "public method2 called" end def method3 puts "public method3 called" method1 self.method1 end end s = Some.new s.method1 s.method2 s.method3
The example explains the usage of public Ruby methods.
def method1 puts "public method1 called" end
The method1 is public, even if we did not specify the public
access modifier. It is because methods are public by default if not specified otherwise.
public def method2 puts "public method2 called" end ...
Methods following the public
keyword are public.
def method3 puts "public method3 called" method1 self.method1 end
From inside the public method3
, we call other public method, with and without the self
keyword.
s = Some.new s.method1 s.method2 s.method3
Public methods are the only methods that can be called outside the definition of a class as shown here.
$ ./public_methods.rb public method1 called public method2 called public method3 called public method1 called public method1 called
Running the example we have this output.
The next example looks at private methods.
#!/usr/bin/ruby class Some def initialize method1 # self.method1 end private def method1 puts "private method1 called" end end s = Some.new # s.method1
Private methods are tightest methods in Ruby. They can be called only inside a class definition and without the self
keyword.
def initialize method1 # self.method1 end
In the constructor of the method, we call the private method1
. Calling the method with the self is commented. Private methods cannot be specified with a receiver.
private def method1 puts "private method1 called" end
Methods following the private
keyword are private in Ruby.
s = Some.new # s.method1
We create an instance of the Some class. Calling the method outside the class definition is prohibited. If we uncomment the line, the Ruby interpreter gives an error.
$ ./private_methods.rb private method called
Output of the example code.
Finally, we will work with protected methods. The distinction between protected and private methods in Ruby is subtle. Protected methods are like private. There is only one small difference. They can be called with the self
keyword specified.
#!/usr/bin/ruby class Some def initialize method1 self.method1 end protected def method1 puts "protected method1 called" end end s = Some.new # s.method1
The above example shows protected method in usage.
def initialize method1 self.method1 end
Protected methods can be called with and without the self
keyword.
protected def method1 puts "protected method1 called" end
Protected methods are preceded by the protected
keyword.
s = Some.new # s.method1
Protected methods cannot be called outside the class definition. Uncommenting the line would lead to an error.
Inheritance
Inheritance is a way to form new classes using classes that have already been defined. The newly formed classes are called derived classes, the classes that we derive from are called base classes. Important benefits of inheritance are code reuse and reduction of complexity of a program. The derived classes (descendants) override or extend the functionality of base classes (ancestors).
#!/usr/bin/ruby class Being def initialize puts "Being class created" end end class Human < Being def initialize super puts "Human class created" end end Being.new Human.new
In this program, we have two classes: a base Being
class and a derived Human
class. The derived class inherits from the base class.
class Human < Being
In Ruby, we use the <
operator to create inheritance relations. The Human
class inherits from the Being
class.
def initialize super puts "Human class created" end
The super
method calls the constructor of the parent class.
Being.new Human.new
We instantiate the Being
and the Human
class.
$ ./inheritance.rb Being class created Being class created Human class created
First the Being
class is created. The derived Human
class also calls the constructor of its parent.
An Object may be involved in complicated relationships. A single object can have multiple ancestors. Ruby has a method ancestors
which gives a list of ancestors for a specific class.
Each Ruby object is automatically a descendant of Object
and BasicObject
classes and of the Kernel
module. They are built-in the core of the Ruby language.
#!/usr/bin/ruby class Being end class Living < Being end class Mammal < Living end class Human < Mammal end p Human.ancestors
We have four classes in this example: a Human
is a Mammal
a Living
and a Being
.
p Human.ancestors
We print the ancestors of a Human class.
$ ./ancestors.rb [Human, Mammal, Living, Being, Object, Kernel, BasicObject]
A Human class has three custom and three built-in ancestors.
A more complex example follows.
#!/usr/bin/ruby class Being @@count = 0 def initialize @@count += 1 puts "Being class created" end def show_count "There are #{@@count} beings" end end class Human < Being def initialize super puts "Human is created" end end class Animal < Being def initialize super puts "Animal is created" end end class Dog < Animal def initialize super puts "Dog is created" end end Human.new d = Dog.new puts d.show_count
We have four classes. The inheritance hierarchy is more complicated. The Human
and the Animal
classes inherit from the Being
class. And the Dog
class inherits directly from the Animal
class and further from the Being
class. We also use a class variable to count the number of beings created.
@@count = 0
We define a class variable. A class variable begins with @@
sigils and it belongs to the class, not to the instance of the class. We use it to count the number of beings created.
def initialize @@count += 1 puts "Being class created" end
Each time the Being
class is instantiated, we increase the @@count
variable by one. This way we keep track of the number of instances created.
class Animal < Being ... class Dog < Animal ...
The Animal
inherits from the Being
and the Dog
inherits from the Animal
. Further, the Dog
inherits from the Being
as well.
Human.new d = Dog.new puts d.show_count
We create instances from the Human
and from the Dog
classes. We call the show_count
method on the Dog
object. The Dog
class has no such method; the grandparent's (Being's) method is called then.
$ ./inheritance2.rb Being class created Human is created Being class created Animal is created Dog is created There are 2 beings
The Human object calls two constructors. The Dog
object calls three constructors. There are two beings instantiated.
Inheritance does not play role in the visibility of methods and data members. This is a notable difference from many common object-oriented programming languages.
In C# or Java, public and protected data members and methods are inherited; private data members and methods are not. In contrast to this, private data members and methods are inherited in Ruby as well. The visibility of data members and methods is not affected by inheritance in Ruby.
#!/usr/bin/ruby class Base def initialize @name = "Base" end private def private_method puts "private method called" end protected def protected_method puts "protected_method called" end public def get_name return @name end end class Derived < Base def public_method private_method protected_method end end d = Derived.new d.public_method puts d.get_name
In the example we have two classes. The Derived
class inherits from the Base
class. It inherits all three methods and one data field.
def public_method private_method protected_method end
In the public_method of the Derived
class we call one private and one protected method. They were defined in the parent class.
d = Derived.new d.public_method puts d.get_name
We create an instance of the Derived
class. We call public_method
, as well as also get_name
, which returns the private @name
variable. Remember that all instance variables are private in Ruby. The get_name method returns the variable, regardless of @name's being private and defined in the parent class.
$ ./inheritance3.rb private method called protected_method called Base
The output of the example confirms that in Ruby language, public, protected, private methods and private member fields are inherited by child objects from their parents.
The super method
The super
method calls a method of the same name in the parent's class. If the method has no arguments it automatically passes all its arguments. If we write super()
no arguments are passed to parent's method.
#!/usr/bin/ruby class Base def show x=0, y=0 p "Base class, x: #{x}, y: #{y}" end end class Derived < Base def show x, y super super x super x, y super() end end d = Derived.new d.show 3, 3
In the example, we have two classes in a hierarchy. They both have a show method. The show method in the Derived class calls the show method in the Base class using the super
method.
def show x, y super super x super x, y super() end
The super
method without any arguments calls the parent's show method with the arguments that were passed to the show method of the Derived
class: here, x=3 and y=3. The super()
method passes no arguments to the parent's show method.
$ ./super.rb "Base class, x: 3, y: 3" "Base class, x: 3, y: 0" "Base class, x: 3, y: 3" "Base class, x: 0, y: 0"
This is the output of the example.
This was the first part of the description of OOP in Ruby.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论