Search
⌘K
    to navigateEnterto select Escto close

    Converting procedural style code to Object Oriented Code

    Let's say that we need to produce a message as shown below.

    1Dear Mike,
    2
    3Thank you for choosing the monthly plan of $19/month.
    4
    5Please note that we also provide annual plan of $190/year which
    6you can upgrade to at anytime.
    7
    8If you need any help then please contact us.
    9- neetoChat team
    

    In the above case the amount and the currency might change.

    We can solve this by writing code like this.

    1currency = "$"
    2monthly_price = 19
    3annual_price = 190
    4
    5greetings = "Dear Mike,"
    6line1 = "Thank you for choosing the monthly plan of #{currency}#{monthly_price}/month."
    7
    8line2 = "Please note that we also provide annual plan of #{currency}#{annual_price}/year"
    9line2 << " which you can upgrade to at anytime."
    10
    11line3 = "If you need any help then please contact us."
    12line4 = "- neetoChat team"
    13
    14puts greetings
    15puts line1
    16puts line2
    17puts line3
    18puts line44
    

    As we have seen before this style of writing code is called "Procedural style of programming".

    Let's take a look at how to solve the same problem using "Object Oriented style of programming". We will start with creating a class called Price.

    1class Price
    2end

    Currently this class has nothing. Let's move all the lines from procedural to object oriented style.

    1class Price
    2  def self.greetings
    3    "Dear Mike,"
    4  end
    5
    6  def self.line1(currency, monthly_price)
    7    "Thank you for choosing the monthly plan of #{currency}#{monthly_price}/month."
    8  end
    9
    10  def self.line2(currency, annual_price)
    11    "Please note that we also provide annual plan of #{currency}#{annual_price}/year" <<
    12    " which you can upgrade to at anytime."
    13  end
    14
    15  def self.line3
    16    "If you need any help then please contact us."
    17  end
    18
    19  def self.line4
    20    "- neetoChat team"
    21  end
    22end
    23
    24currency = "$"
    25monthly_price = 19
    26annual_price = 190
    27
    28puts Price.greetings
    29puts Price.line1(currency, monthly_price)
    30puts Price.line2(currency, monthly_price)
    31puts Price.line3
    32puts Price.line4

    We created a few "class methods" and moved the procedural code there.

    For methods "line1" and "line2" we need to pass currency to both the methods. why do we need to pass same currency two times. We need to do that here because the class Price does not hold currency.

    Rather than passing currency twice we will let the class hold the value of currency and then use it when we need currency.

    In Ruby when we instantiate a class then initialize method is called. That's a good place to pass any state level information for that class.

    1class Price
    2  def initialize(currency)
    3    @currency = currency
    4  end
    5 end

    Now the instantiated object will hold the state called currency which can be used by other methods. Also we need to change methods from class methods to instance methods. After the change the class looks like this.

    1class Price
    2  def initialize(currency)
    3    @currency = currency
    4  end
    5
    6  def greetings
    7    "Dear Mike,"
    8  end
    9
    10  def line1(monthly_price)
    11    "Thank you for choosing the monthly plan of #{@currency}#{monthly_price}/month."
    12  end
    13
    14  def line2(annual_price)
    15    "Please note that we also provide annual plan of #{@currency}#{annual_price}/year" <<
    16    " which you can upgrade to at anytime."
    17  end
    18
    19  def line3
    20    "If you need any help then please contact us."
    21  end
    22
    23  def line4
    24    "- neetoChat team"
    25  end
    26end
    27
    28currency = "$"
    29monthly_price = 19
    30annual_price = 190
    31
    32price = Price.new(currency)
    33puts price.greetings
    34puts price.line1(monthly_price)
    35puts price.line2(annual_price)
    36puts price.line3
    37puts price.line4

    In the above case methods "line1" and "line2" are reaching out to "@currency". This is not ideal. A class should be able to control what is available and what is not.

    In this case we can use attr_reader to make currency available to all the methods. Note these methods need to use currency and not @currency.

    Here is the modified solution.

    1class Price
    2
    3  attr_reader :currency
    4
    5  def initialize(currency)
    6    @currency = currency
    7  end
    8
    9  def greetings
    10    "Dear Mike,"
    11  end
    12
    13  def line1(monthly_price)
    14    "Thank you for choosing the monthly plan of #{currency}#{monthly_price}/month."
    15  end
    16
    17  def line2(annual_price)
    18    "Please note that we also provide annual plan of #{currency}#{annual_price}/year" <<
    19    " which you can upgrade to at anytime."
    20  end
    21
    22  def line3
    23    "If you need any help then please contact us."
    24  end
    25
    26  def line4
    27    "- neetoChat team"
    28  end
    29end
    30
    31currency = "$"
    32monthly_price = 19
    33annual_price = 190
    34
    35price = Price.new(currency)
    36puts price.greetings
    37puts price.line1(monthly_price)
    38puts price.line2(annual_price)
    39puts price.line3
    40puts price.line4

    So far we have been instantiating an object and on that object we have been invoking all these methods. However we can move the call to these methods to inside the class and have only one method from outside to call it.

    Here is a modified solution.

    1class Price
    2
    3  attr_reader :currency
    4
    5  def initialize(currency)
    6    @currency = currency
    7  end
    8
    9  def message(monthly_price, annual_price)
    10    msg = []
    11    msg << greetings
    12    msg << line1(monthly_price)
    13    msg << line2(annual_price)
    14    msg << line3
    15    msg << line4
    16    msg.each { |m| puts m }
    17  end
    18
    19  private
    20
    21  def greetings
    22    "Dear Mike,"
    23  end
    24
    25  def line1(monthly_price)
    26    "Thank you for choosing the monthly plan of #{currency}#{monthly_price}/month."
    27  end
    28
    29  def line2(annual_price)
    30    "Please note that we also provide annual plan of #{currency}#{annual_price}/year" <<
    31    " which you can upgrade to at anytime."
    32  end
    33
    34  def line3
    35    "If you need any help then please contact us."
    36  end
    37
    38  def line4
    39    "- neetoChat team"
    40  end
    41end
    42
    43currency = "$"
    44monthly_price = 19
    45annual_price = 190
    46
    47price = Price.new(currency)
    48price.message(monthly_price, annual_price)

    In the above case while calling the method message we are passing "monthly_price" and "annual_price". We can pass on the pricing information when we are instantiating the class. Let's do that.

    Here is the modified code.

    1class Price
    2
    3  attr_reader :currency, :monthly_price, :annual_price
    4
    5  def initialize(currency, monthly_price, annual_price)
    6    @currency = currency
    7    @monthly_price = monthly_price
    8    @annual_price = annual_price
    9  end
    10
    11  def message
    12    msg = []
    13    msg << greetings
    14    msg << line1
    15    msg << line2
    16    msg << line3
    17    msg << line4
    18    msg.each { |m| puts m }
    19  end
    20
    21  private
    22
    23  def greetings
    24    "Dear Mike,"
    25  end
    26
    27  def line1
    28    "Thank you for choosing the monthly plan of #{currency}#{monthly_price}/month."
    29  end
    30
    31  def line2
    32    "Please note that we also provide annual plan of #{currency}#{annual_price}/year" <<
    33    " which you can upgrade to at anytime."
    34  end
    35
    36  def line3
    37    "If you need any help then please contact us."
    38  end
    39
    40  def line4
    41    "- neetoChat team"
    42  end
    43end
    44
    45currency = "$"
    46monthly_price = 19
    47annual_price = 190
    48price = Price.new(currency, monthly_price, annual_price)
    49price.message
    Previous
    Next