0
\$\begingroup\$

I have implemented a very basic sandwich (sub) shop which a user can add extra toppings at an additional cost. The cost is calculated and the contents of the sandwich is outputted.

I am learning design patterns and the book I am learning from (Head First Design Patterns) is in Java, which I am not too familiar with, so I may be making some errors.

Sub.h

#ifndef SUB_H
#define SUB_H

//Class Sub: Abstract Base class. 
//Following the decorator pattern

#include <string>
#include <memory>

class Sub
{
  public:
    virtual double getCost() = 0;
    virtual std::string getToppings() = 0;
    virtual ~Sub() = 0;
};

class Plain: public Sub
{
  public:
    double getCost() override;
    std::string getToppings() override;
};

class ExtraCheese: public Sub
{
  public:
    ExtraCheese(std::shared_ptr<Sub> s) : sub(s) {}
    double getCost() override;
    std::string getToppings() override;
  private:
    std::shared_ptr<Sub> sub;
};

class ExtraMeat: public Sub
{
  public:
    ExtraMeat(std::shared_ptr<Sub> s) : sub(s) {}
    double getCost() override;
    std::string getToppings() override;
  private:
    std::shared_ptr<Sub> sub;
};

class ExtraSauce: public Sub
{
  public:
    ExtraSauce(std::shared_ptr<Sub> s) : sub(s) {}
    double getCost() override;
    std::string getToppings() override;
  private:
    std::shared_ptr<Sub> sub;
};

#endif

Sub.cpp

#include "Sub.h"

inline Sub::~Sub(){}

//class Plain : public Sub
double Plain::getCost() 
{
  return 3.75;
}

std::string Plain::getToppings()
{
  return "Basic Sub";
}

//class ExtraCheese : public Sub

double ExtraCheese::getCost()
{
  return sub->getCost() + 0.75;
}

std::string ExtraCheese::getToppings()
{
  return sub->getToppings() + ", Extra Cheese";
}

//class ExtraMeat : public Sub
double ExtraMeat::getCost()
{
  return sub->getCost() + 1.50;
}

std::string ExtraMeat::getToppings()
{
  return sub->getToppings() + ", Extra Meat";
}

//class ExtraSauce : public Sub
double ExtraSauce::getCost()
{
  return sub->getCost() + 0.15;
}

std::string ExtraSauce::getToppings()
{
  return sub->getToppings() + ", Extra Sauce";
}

main.cpp

#include <iostream>
#include <memory>
#include "Sub.h"

int main()
{
  std::shared_ptr<Sub> s(new Plain());

  s = std::make_shared<ExtraCheese>(s); 
  s = std::make_shared<ExtraMeat>(s);
  s = std::make_shared<ExtraSauce>(s);

  std::cout<<"COST: "<< s->getCost() <<std::endl;
  std::cout<<"Toppings: " << s->getToppings() <<std::endl;
}
\$\endgroup\$
1
  • 3
    \$\begingroup\$ You should probably use int for monetary units. You don't want to have rounding errors. Use int and make the price in cent (you can put the decimal point in when printing). \$\endgroup\$ Nov 8, 2013 at 5:49

1 Answer 1

4
\$\begingroup\$

No:

An object "Sub" and a decorator "Topping" implement the same interface. In addition a decorator takes an item (of the same interface) that it is decorating.
This is not quite what you have done.

What if I want extra cheese and meat?

You need something more like this:

class Price
{
    public:
       virtual     ~Price()   = 0;
       virtual int getPrice() = 0;
};

class Sub: public Price
{
    public:
        int getPrice() override {return 375;}
};

class ExtraCheese: public Price
{
    std::unique_ptr<Price>   item
    public:
        ExtraCheese(std::unique_ptr<Price>&& item)
             : item(std::move(item))
        {}
         int getPrice() override {return item->getPrice() + 25;}
};

int main()
{
    std::unique_ptr<Price>   sub(new Sub);
    std::unique_ptr<Price>   subCheese(new ExtraCheese(sub));
    std::unique_ptr<Price>   subCheeseMeat(new ExtraMeat(subCheese));

    std::cout << subCheeseMeat->getPrice();
}
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.