Initiating an action based on product type I am starting my studies with Ruby and OO and I have received a test to do about OO. I am looking for new ways to improve the scenario following object-oriented concepts. Is there a better way to develop this design applying polymorphism? 

Here is my problem:


If the product is physical, I have to generate a shipping label.
If it's a book, I have to mention that this product doesn't have taxes.
If the product is a membership, I have to activate the signature and notify the buyer via email.
If the product is digital, I have to send an email for the buyer and give a $10 discount for this product.




class Product
  attr_reader :name, :description, :type, :amount
  include Shipping
  include Discount

    def initialize(name, description, type, amount)
        @name = name
        @description = description
        @type = type
        @amount = amount
    end 
end

class Physical &lt; Product
    def initialize(name, description, type, amount)
        super(name, description, type, amount)
    end

    def shipping
        case @type
            when :book
                create_shipping_label
                notify_buyer_product_without_taxes
            else
                create_shipping_label
            end
    end

    def discount
        discount_for_physical_product = 0.0
      return discount_for_physical_product
    end
end

class Membership &lt; Product
    attr_reader :membership_status

    def initialize(name, description, type, amount)
        super(name, description, type, amount)
    end

  def activate_membership()
    @membership_status = true;
  end

  def shipping
    notify_buyer_via_email
    activate_membership
  end

  def discount
    discount_for_membership_product = 0
    return discount_for_membership_product
  end
end

class Digital &lt; Product

    def initialize(name, description, type, amount)
        super(name, description, type, amount)
    end

  def shipping
    notify_buyer_via_email
  end   

  def discount
    discount_for_digital_product = 10.00
    return discount_for_digital_product
  end
end

module Discount

    def prepare_discount(order)
        total_discount = 0
        order.get_items.each do |item|
             total_discount += item.product.discount
        end
        return total_discount
    end

    def discount
        discount_default = 0.0
        return discount_default
    end
end
You have a conditional based on the type of object. You can apply the Replace Conditional with Polymorphism refactoring pattern. 

In this case, you might have a base class Product, with subclasses DigitalProduct and PhysicalProduct which each implement discount(). I don't think it's sensible to have a MembershipProduct class - membership should be related to the buyer. From an OO perspective, it should feel wrong when you have methods like discount_for_X() - the method should be part of the respective class so that you can make use of polymorphism.