Initiating an action based on product type











up vote
1
down vote

favorite












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:




  1. If the product is physical, I have to generate a shipping label.


  2. If it's a book, I have to mention that this product doesn't have taxes.


  3. If the product is a membership, I have to activate the signature and notify the buyer via email.


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









share|improve this question
















bumped to the homepage by Community 21 hours ago


This question has answers that may be good or bad; the system has marked it active so that they can be reviewed.



















    up vote
    1
    down vote

    favorite












    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:




    1. If the product is physical, I have to generate a shipping label.


    2. If it's a book, I have to mention that this product doesn't have taxes.


    3. If the product is a membership, I have to activate the signature and notify the buyer via email.


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









    share|improve this question
















    bumped to the homepage by Community 21 hours ago


    This question has answers that may be good or bad; the system has marked it active so that they can be reviewed.

















      up vote
      1
      down vote

      favorite









      up vote
      1
      down vote

      favorite











      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:




      1. If the product is physical, I have to generate a shipping label.


      2. If it's a book, I have to mention that this product doesn't have taxes.


      3. If the product is a membership, I have to activate the signature and notify the buyer via email.


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









      share|improve this question















      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:




      1. If the product is physical, I have to generate a shipping label.


      2. If it's a book, I have to mention that this product doesn't have taxes.


      3. If the product is a membership, I have to activate the signature and notify the buyer via email.


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






      object-oriented ruby






      share|improve this question















      share|improve this question













      share|improve this question




      share|improve this question








      edited Feb 8 '17 at 6:16









      Jamal

      30.2k11115226




      30.2k11115226










      asked Feb 8 '17 at 4:10









      junis087678

      112




      112





      bumped to the homepage by Community 21 hours ago


      This question has answers that may be good or bad; the system has marked it active so that they can be reviewed.







      bumped to the homepage by Community 21 hours ago


      This question has answers that may be good or bad; the system has marked it active so that they can be reviewed.
























          2 Answers
          2






          active

          oldest

          votes

















          up vote
          0
          down vote













          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.






          share|improve this answer























          • thank you ! One question, if business rules for shipping and discount are in product class is not wrong ? I mean would it be better if I use the polymorphism in this case and call methods from shipping and discount module to deal with it ? This way I would use polymorphism and follow the first's SOLID rule )Single responsibility principle). Thank you!
            – junis087678
            Feb 8 '17 at 5:33










          • It's a bit difficult to understand what you're asking. To follow site rules, you should post a completed sample in order to get appropriate feedback. See on-topic.
            – jsuth
            Feb 8 '17 at 5:39




















          up vote
          0
          down vote













          Disclaimer: I'm not a Ruby expert



          Type parameter



          The main thing that bothers me with you code is the type parameter given when constructing a Product's instance. This goes against OO principles and leads to bad code for the following reason: you have to manage conditional explicitely in code with control structures (if, switch) instead of delegating this responsibility to the compiler/interpreter by using polymorphism.



          Removing this would need to introduce a both Book class and a GenericProduct class which is basically representing all physical products but books.



          Common discount method



          Another thing is that the discount method is common to all products and differs only in the data (and not in the behavior). This can be implemented in Product and request the discount value in the constructor.



          Create local variable and directly return it



          This is useless and only introduce visual noise. You can directly return the value.



          Similitude between Membership and Digital Product



          It looks like Membership is also a special kind of digital product and that a relationship between them can exist (they both require to send an email when shipping). However I'm not entirely sure about that so feel free to ignore the end of the resulting code listing.



          Reviewed code



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

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

          def discount
          return @discount
          end
          end

          class PhysicalProduct < Product
          def initialize(name, description, amount)
          super(name, description, amount, 0.0)
          end

          def shipping
          create_shipping_label
          notify_buyer_product_without_taxes if free_of_taxes
          end
          end

          class GenericProduct < PhysicalProduct
          def initialize(name, description, amount)
          super(name, description, amount)
          end

          def free_of_taxes
          return false
          end
          end

          class Book < PhysicalProduct
          def initialize(name, description, amount)
          super(name, description, amount)
          end

          def free_of_taxes
          return true
          end
          end

          class DigitalProduct < Product

          def initialize(name, description, amount, discount = 10.00)
          super(name, description, amount, discount)
          end

          def shipping
          notify_buyer_via_email
          end
          end

          class Membership < DigitalProduct
          attr_reader :membership_status

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

          def activate_membership()
          @membership_status = true;
          end

          def shipping
          super
          activate_membership
          end
          end





          share|improve this answer





















            Your Answer





            StackExchange.ifUsing("editor", function () {
            return StackExchange.using("mathjaxEditing", function () {
            StackExchange.MarkdownEditor.creationCallbacks.add(function (editor, postfix) {
            StackExchange.mathjaxEditing.prepareWmdForMathJax(editor, postfix, [["\$", "\$"]]);
            });
            });
            }, "mathjax-editing");

            StackExchange.ifUsing("editor", function () {
            StackExchange.using("externalEditor", function () {
            StackExchange.using("snippets", function () {
            StackExchange.snippets.init();
            });
            });
            }, "code-snippets");

            StackExchange.ready(function() {
            var channelOptions = {
            tags: "".split(" "),
            id: "196"
            };
            initTagRenderer("".split(" "), "".split(" "), channelOptions);

            StackExchange.using("externalEditor", function() {
            // Have to fire editor after snippets, if snippets enabled
            if (StackExchange.settings.snippets.snippetsEnabled) {
            StackExchange.using("snippets", function() {
            createEditor();
            });
            }
            else {
            createEditor();
            }
            });

            function createEditor() {
            StackExchange.prepareEditor({
            heartbeatType: 'answer',
            convertImagesToLinks: false,
            noModals: true,
            showLowRepImageUploadWarning: true,
            reputationToPostImages: null,
            bindNavPrevention: true,
            postfix: "",
            imageUploader: {
            brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
            contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
            allowUrls: true
            },
            onDemand: true,
            discardSelector: ".discard-answer"
            ,immediatelyShowMarkdownHelp:true
            });


            }
            });














             

            draft saved


            draft discarded


















            StackExchange.ready(
            function () {
            StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f154772%2finitiating-an-action-based-on-product-type%23new-answer', 'question_page');
            }
            );

            Post as a guest















            Required, but never shown

























            2 Answers
            2






            active

            oldest

            votes








            2 Answers
            2






            active

            oldest

            votes









            active

            oldest

            votes






            active

            oldest

            votes








            up vote
            0
            down vote













            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.






            share|improve this answer























            • thank you ! One question, if business rules for shipping and discount are in product class is not wrong ? I mean would it be better if I use the polymorphism in this case and call methods from shipping and discount module to deal with it ? This way I would use polymorphism and follow the first's SOLID rule )Single responsibility principle). Thank you!
              – junis087678
              Feb 8 '17 at 5:33










            • It's a bit difficult to understand what you're asking. To follow site rules, you should post a completed sample in order to get appropriate feedback. See on-topic.
              – jsuth
              Feb 8 '17 at 5:39

















            up vote
            0
            down vote













            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.






            share|improve this answer























            • thank you ! One question, if business rules for shipping and discount are in product class is not wrong ? I mean would it be better if I use the polymorphism in this case and call methods from shipping and discount module to deal with it ? This way I would use polymorphism and follow the first's SOLID rule )Single responsibility principle). Thank you!
              – junis087678
              Feb 8 '17 at 5:33










            • It's a bit difficult to understand what you're asking. To follow site rules, you should post a completed sample in order to get appropriate feedback. See on-topic.
              – jsuth
              Feb 8 '17 at 5:39















            up vote
            0
            down vote










            up vote
            0
            down vote









            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.






            share|improve this answer














            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.







            share|improve this answer














            share|improve this answer



            share|improve this answer








            edited Feb 8 '17 at 5:28

























            answered Feb 8 '17 at 5:15









            jsuth

            597214




            597214












            • thank you ! One question, if business rules for shipping and discount are in product class is not wrong ? I mean would it be better if I use the polymorphism in this case and call methods from shipping and discount module to deal with it ? This way I would use polymorphism and follow the first's SOLID rule )Single responsibility principle). Thank you!
              – junis087678
              Feb 8 '17 at 5:33










            • It's a bit difficult to understand what you're asking. To follow site rules, you should post a completed sample in order to get appropriate feedback. See on-topic.
              – jsuth
              Feb 8 '17 at 5:39




















            • thank you ! One question, if business rules for shipping and discount are in product class is not wrong ? I mean would it be better if I use the polymorphism in this case and call methods from shipping and discount module to deal with it ? This way I would use polymorphism and follow the first's SOLID rule )Single responsibility principle). Thank you!
              – junis087678
              Feb 8 '17 at 5:33










            • It's a bit difficult to understand what you're asking. To follow site rules, you should post a completed sample in order to get appropriate feedback. See on-topic.
              – jsuth
              Feb 8 '17 at 5:39


















            thank you ! One question, if business rules for shipping and discount are in product class is not wrong ? I mean would it be better if I use the polymorphism in this case and call methods from shipping and discount module to deal with it ? This way I would use polymorphism and follow the first's SOLID rule )Single responsibility principle). Thank you!
            – junis087678
            Feb 8 '17 at 5:33




            thank you ! One question, if business rules for shipping and discount are in product class is not wrong ? I mean would it be better if I use the polymorphism in this case and call methods from shipping and discount module to deal with it ? This way I would use polymorphism and follow the first's SOLID rule )Single responsibility principle). Thank you!
            – junis087678
            Feb 8 '17 at 5:33












            It's a bit difficult to understand what you're asking. To follow site rules, you should post a completed sample in order to get appropriate feedback. See on-topic.
            – jsuth
            Feb 8 '17 at 5:39






            It's a bit difficult to understand what you're asking. To follow site rules, you should post a completed sample in order to get appropriate feedback. See on-topic.
            – jsuth
            Feb 8 '17 at 5:39














            up vote
            0
            down vote













            Disclaimer: I'm not a Ruby expert



            Type parameter



            The main thing that bothers me with you code is the type parameter given when constructing a Product's instance. This goes against OO principles and leads to bad code for the following reason: you have to manage conditional explicitely in code with control structures (if, switch) instead of delegating this responsibility to the compiler/interpreter by using polymorphism.



            Removing this would need to introduce a both Book class and a GenericProduct class which is basically representing all physical products but books.



            Common discount method



            Another thing is that the discount method is common to all products and differs only in the data (and not in the behavior). This can be implemented in Product and request the discount value in the constructor.



            Create local variable and directly return it



            This is useless and only introduce visual noise. You can directly return the value.



            Similitude between Membership and Digital Product



            It looks like Membership is also a special kind of digital product and that a relationship between them can exist (they both require to send an email when shipping). However I'm not entirely sure about that so feel free to ignore the end of the resulting code listing.



            Reviewed code



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

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

            def discount
            return @discount
            end
            end

            class PhysicalProduct < Product
            def initialize(name, description, amount)
            super(name, description, amount, 0.0)
            end

            def shipping
            create_shipping_label
            notify_buyer_product_without_taxes if free_of_taxes
            end
            end

            class GenericProduct < PhysicalProduct
            def initialize(name, description, amount)
            super(name, description, amount)
            end

            def free_of_taxes
            return false
            end
            end

            class Book < PhysicalProduct
            def initialize(name, description, amount)
            super(name, description, amount)
            end

            def free_of_taxes
            return true
            end
            end

            class DigitalProduct < Product

            def initialize(name, description, amount, discount = 10.00)
            super(name, description, amount, discount)
            end

            def shipping
            notify_buyer_via_email
            end
            end

            class Membership < DigitalProduct
            attr_reader :membership_status

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

            def activate_membership()
            @membership_status = true;
            end

            def shipping
            super
            activate_membership
            end
            end





            share|improve this answer

























              up vote
              0
              down vote













              Disclaimer: I'm not a Ruby expert



              Type parameter



              The main thing that bothers me with you code is the type parameter given when constructing a Product's instance. This goes against OO principles and leads to bad code for the following reason: you have to manage conditional explicitely in code with control structures (if, switch) instead of delegating this responsibility to the compiler/interpreter by using polymorphism.



              Removing this would need to introduce a both Book class and a GenericProduct class which is basically representing all physical products but books.



              Common discount method



              Another thing is that the discount method is common to all products and differs only in the data (and not in the behavior). This can be implemented in Product and request the discount value in the constructor.



              Create local variable and directly return it



              This is useless and only introduce visual noise. You can directly return the value.



              Similitude between Membership and Digital Product



              It looks like Membership is also a special kind of digital product and that a relationship between them can exist (they both require to send an email when shipping). However I'm not entirely sure about that so feel free to ignore the end of the resulting code listing.



              Reviewed code



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

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

              def discount
              return @discount
              end
              end

              class PhysicalProduct < Product
              def initialize(name, description, amount)
              super(name, description, amount, 0.0)
              end

              def shipping
              create_shipping_label
              notify_buyer_product_without_taxes if free_of_taxes
              end
              end

              class GenericProduct < PhysicalProduct
              def initialize(name, description, amount)
              super(name, description, amount)
              end

              def free_of_taxes
              return false
              end
              end

              class Book < PhysicalProduct
              def initialize(name, description, amount)
              super(name, description, amount)
              end

              def free_of_taxes
              return true
              end
              end

              class DigitalProduct < Product

              def initialize(name, description, amount, discount = 10.00)
              super(name, description, amount, discount)
              end

              def shipping
              notify_buyer_via_email
              end
              end

              class Membership < DigitalProduct
              attr_reader :membership_status

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

              def activate_membership()
              @membership_status = true;
              end

              def shipping
              super
              activate_membership
              end
              end





              share|improve this answer























                up vote
                0
                down vote










                up vote
                0
                down vote









                Disclaimer: I'm not a Ruby expert



                Type parameter



                The main thing that bothers me with you code is the type parameter given when constructing a Product's instance. This goes against OO principles and leads to bad code for the following reason: you have to manage conditional explicitely in code with control structures (if, switch) instead of delegating this responsibility to the compiler/interpreter by using polymorphism.



                Removing this would need to introduce a both Book class and a GenericProduct class which is basically representing all physical products but books.



                Common discount method



                Another thing is that the discount method is common to all products and differs only in the data (and not in the behavior). This can be implemented in Product and request the discount value in the constructor.



                Create local variable and directly return it



                This is useless and only introduce visual noise. You can directly return the value.



                Similitude between Membership and Digital Product



                It looks like Membership is also a special kind of digital product and that a relationship between them can exist (they both require to send an email when shipping). However I'm not entirely sure about that so feel free to ignore the end of the resulting code listing.



                Reviewed code



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

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

                def discount
                return @discount
                end
                end

                class PhysicalProduct < Product
                def initialize(name, description, amount)
                super(name, description, amount, 0.0)
                end

                def shipping
                create_shipping_label
                notify_buyer_product_without_taxes if free_of_taxes
                end
                end

                class GenericProduct < PhysicalProduct
                def initialize(name, description, amount)
                super(name, description, amount)
                end

                def free_of_taxes
                return false
                end
                end

                class Book < PhysicalProduct
                def initialize(name, description, amount)
                super(name, description, amount)
                end

                def free_of_taxes
                return true
                end
                end

                class DigitalProduct < Product

                def initialize(name, description, amount, discount = 10.00)
                super(name, description, amount, discount)
                end

                def shipping
                notify_buyer_via_email
                end
                end

                class Membership < DigitalProduct
                attr_reader :membership_status

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

                def activate_membership()
                @membership_status = true;
                end

                def shipping
                super
                activate_membership
                end
                end





                share|improve this answer












                Disclaimer: I'm not a Ruby expert



                Type parameter



                The main thing that bothers me with you code is the type parameter given when constructing a Product's instance. This goes against OO principles and leads to bad code for the following reason: you have to manage conditional explicitely in code with control structures (if, switch) instead of delegating this responsibility to the compiler/interpreter by using polymorphism.



                Removing this would need to introduce a both Book class and a GenericProduct class which is basically representing all physical products but books.



                Common discount method



                Another thing is that the discount method is common to all products and differs only in the data (and not in the behavior). This can be implemented in Product and request the discount value in the constructor.



                Create local variable and directly return it



                This is useless and only introduce visual noise. You can directly return the value.



                Similitude between Membership and Digital Product



                It looks like Membership is also a special kind of digital product and that a relationship between them can exist (they both require to send an email when shipping). However I'm not entirely sure about that so feel free to ignore the end of the resulting code listing.



                Reviewed code



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

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

                def discount
                return @discount
                end
                end

                class PhysicalProduct < Product
                def initialize(name, description, amount)
                super(name, description, amount, 0.0)
                end

                def shipping
                create_shipping_label
                notify_buyer_product_without_taxes if free_of_taxes
                end
                end

                class GenericProduct < PhysicalProduct
                def initialize(name, description, amount)
                super(name, description, amount)
                end

                def free_of_taxes
                return false
                end
                end

                class Book < PhysicalProduct
                def initialize(name, description, amount)
                super(name, description, amount)
                end

                def free_of_taxes
                return true
                end
                end

                class DigitalProduct < Product

                def initialize(name, description, amount, discount = 10.00)
                super(name, description, amount, discount)
                end

                def shipping
                notify_buyer_via_email
                end
                end

                class Membership < DigitalProduct
                attr_reader :membership_status

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

                def activate_membership()
                @membership_status = true;
                end

                def shipping
                super
                activate_membership
                end
                end






                share|improve this answer












                share|improve this answer



                share|improve this answer










                answered Jul 24 at 8:33









                Spotted

                54928




                54928






























                     

                    draft saved


                    draft discarded



















































                     


                    draft saved


                    draft discarded














                    StackExchange.ready(
                    function () {
                    StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f154772%2finitiating-an-action-based-on-product-type%23new-answer', 'question_page');
                    }
                    );

                    Post as a guest















                    Required, but never shown





















































                    Required, but never shown














                    Required, but never shown












                    Required, but never shown







                    Required, but never shown

































                    Required, but never shown














                    Required, but never shown












                    Required, but never shown







                    Required, but never shown







                    Popular posts from this blog

                    Costa Masnaga

                    Fotorealismo

                    Sidney Franklin