Skip to content

Instantly share code, notes, and snippets.

@Sh0cko
Last active October 12, 2025 23:40
Show Gist options
  • Select an option

  • Save Sh0cko/50b4a84ed081fbeaf0390feb93662f6c to your computer and use it in GitHub Desktop.

Select an option

Save Sh0cko/50b4a84ed081fbeaf0390feb93662f6c to your computer and use it in GitHub Desktop.

CellShop Practica - C++

Joel Cuevas Estrada - 22210298

Codigo incorrecto

#include <iostream>
#include <string>
#include <vector>
#include <iomanip>
using namespace std;

struct Smartphone {
    string name;
    string brand;
    double price;
    int stock;
};

class InventoryAndBilling {
public:
    vector<Smartphone*> phones;
    double totalSales = 0;
    int invoiceCount = 0;

    void addPhone(string n, string b, double p, int s) {
        Smartphone* ph = new Smartphone();
        ph->name = n;
        ph->brand = b;
        ph->price = p;
        ph->stock = s;
        phones.push_back(ph);
        cout << "Added phone: " << n << " - Stock: " << s << endl;
    }

    void showPhones() {
        cout << "\n=== INVENTORY ===\n";
        for (int i = 0; i < phones.size(); i++) {
            cout << i << ") " << phones[i]->brand << " " << phones[i]->name
                 << " | $" << phones[i]->price
                 << " | Stock: " << phones[i]->stock << endl;
        }
    }

    void sellPhone(int index, int quantity) {
        if (index < 0 || index >= phones.size()) {
            cout << "Invalid index" << endl;
            return;
        }
        if (phones[index]->stock < quantity) {
            cout << "Not enough stock!" << endl;
            return;
        }

        phones[index]->stock -= quantity;
        double total = phones[index]->price * quantity;
        totalSales += total;
        invoiceCount++;

        cout << "\n=== INVOICE #" << invoiceCount << " ===" << endl;
        cout << phones[index]->brand << " " << phones[index]->name << endl;
        cout << "Qty: " << quantity << endl;
        cout << "Total: $" << fixed << setprecision(2) << total << endl;
        cout << "======================" << endl;
    }

    void removePhone(int index) {
        if (index < 0 || index >= phones.size()) {
            cout << "Invalid index" << endl;
            return;
        }
        cout << "Removing: " << phones[index]->name << endl;
        delete phones[index];
        phones.erase(phones.begin() + index);
    }

    void showSummary() {
        cout << "\n=== SUMMARY ===\n";
        cout << "Total invoices: " << invoiceCount << endl;
        cout << "Total sales: $" << totalSales << endl;
        cout << "Remaining phones: " << phones.size() << endl;
    }

    // Duplicated logic: manually adjusts stock (used nowhere properly)
    void adjustStock(string phoneName, int newStock) {
        for (int i = 0; i < phones.size(); i++) {
            if (phones[i]->name == phoneName) {
                phones[i]->stock = newStock;
                cout << "Stock updated for " << phoneName << ": " << newStock << endl;
                break;
            }
        }
    }

    // Bad smell: mixed logic for billing and inventory reports
    void exportReport() {
        cout << "\n=== FULL REPORT ===\n";
        for (int i = 0; i < phones.size(); i++) {
            cout << phones[i]->brand << " " << phones[i]->name
                 << " | Stock: " << phones[i]->stock
                 << " | Price: " << phones[i]->price << endl;
        }
        cout << "Total sales: $" << totalSales << endl;
        cout << "Invoices made: " << invoiceCount << endl;
        cout << "======================\n";
    }

    // Memory leak risk if not called
    ~InventoryAndBilling() {
        for (auto p : phones) {
            delete p;
        }
    }
};

int main() {
    InventoryAndBilling store;
    store.addPhone("iPhone 15", "Apple", 1099.99, 10);
    store.addPhone("Galaxy S24", "Samsung", 899.49, 7);
    store.addPhone("Pixel 9", "Google", 799.99, 5);

    store.showPhones();
    store.sellPhone(0, 2);
    store.sellPhone(2, 1);
    store.removePhone(1);
    store.adjustStock("iPhone 15", 5);
    store.exportReport();
    store.showSummary();
}

Problemas detectados

  • God Class = InventoryAndBilling mezcla responsabilidades de inventario y facturación.
  • Memory leaks = Usa punteros crudos en lugar de unique_ptr o valores.
  • Duplicated code = Lógica repetida en adjustStock, removePhone, showPhones.
  • No encapsulación = Acceso público a casi todo.
  • Magic numbers = Precios y cantidades “hardcodeados” en main().
  • Mixed responsibilities = Facturación y gestión del inventario en la misma clase.
  • Tight coupling = Todo depende directamente del vector global phones.
  • Inconsistent naming = exportReport, showSummary, showPhones — sin convención uniforme.

Refactorizado con SRP (Single Responsability Principle)

#include <iostream>
#include <string>
#include <vector>
#include <iomanip>
using namespace std;

struct Smartphone {
    string name;
    string brand;
    double price;
    int stock;
};

// ======================= INVENTARIO =======================
class Inventory {
private:
    vector<Smartphone> phones;

public:
    void addPhone(const string& name, const string& brand, double price, int stock) {
        phones.push_back({name, brand, price, stock});
        cout << "✅ Agregado: " << brand << " " << name << " (Stock: " << stock << ")\n";
    }

    void removePhone(int index) {
        if (index < 0 || index >= phones.size()) {
            cout << "❌ Índice inválido.\n";
            return;
        }
        cout << "🗑️ Eliminado: " << phones[index].brand << " " << phones[index].name << "\n";
        phones.erase(phones.begin() + index);
    }

    void updateStock(const string& name, int newStock) {
        for (auto& phone : phones) {
            if (phone.name == name) {
                phone.stock = newStock;
                cout << "🔄 Stock actualizado para " << name << ": " << newStock << "\n";
                return;
            }
        }
        cout << "⚠️ No se encontró el teléfono: " << name << "\n";
    }

    vector<Smartphone>& getPhones() { return phones; }
    const vector<Smartphone>& getPhones() const { return phones; }

    void showPhones() const {
        cout << "\n📦 INVENTARIO:\n";
        for (size_t i = 0; i < phones.size(); ++i) {
            const auto& p = phones[i];
            cout << i << ") " << p.brand << " " << p.name
                 << " | $" << p.price << " | Stock: " << p.stock << "\n";
        }
    }
};

// ======================= FACTURACIÓN =======================
class Billing {
private:
    double totalSales = 0;
    int invoiceCount = 0;

public:
    void sellPhone(Inventory& inventory, int index, int quantity) {
        auto& phones = inventory.getPhones();
        if (index < 0 || index >= phones.size()) {
            cout << "❌ Índice inválido.\n";
            return;
        }
        Smartphone& phone = phones[index];

        if (phone.stock < quantity) {
            cout << "⚠️ Stock insuficiente.\n";
            return;
        }

        phone.stock -= quantity;
        double total = phone.price * quantity;
        totalSales += total;
        invoiceCount++;

        printInvoice(phone, quantity, total);
    }

    void printInvoice(const Smartphone& phone, int quantity, double total) const {
        cout << "\n🧾 FACTURA #" << invoiceCount << "\n";
        cout << "Producto: " << phone.brand << " " << phone.name << "\n";
        cout << "Cantidad: " << quantity << "\n";
        cout << "Total: $" << fixed << setprecision(2) << total << "\n";
        cout << "============================\n";
    }

    double getTotalSales() const { return totalSales; }
    int getInvoiceCount() const { return invoiceCount; }
};

// ======================= REPORTES =======================
class Report {
public:
    static void showSummary(const Billing& billing, const Inventory& inventory) {
        cout << "\n📊 RESUMEN:\n";
        cout << "Facturas generadas: " << billing.getInvoiceCount() << "\n";
        cout << "Ventas totales: $" << billing.getTotalSales() << "\n";
        cout << "Productos restantes: " << inventory.getPhones().size() << "\n";
    }

    static void exportReport(const Billing& billing, const Inventory& inventory) {
        cout << "\n🧾 REPORTE COMPLETO\n";
        for (const auto& p : inventory.getPhones()) {
            cout << p.brand << " " << p.name
                 << " | Stock: " << p.stock
                 << " | Precio: $" << p.price << "\n";
        }
        cout << "Total ventas: $" << billing.getTotalSales() << "\n";
        cout << "Facturas: " << billing.getInvoiceCount() << "\n";
        cout << "============================\n";
    }
};

// ======================= PROGRAMA PRINCIPAL =======================
int main() {
    Inventory inventory;
    Billing billing;

    inventory.addPhone("iPhone 15", "Apple", 1099.99, 10);
    inventory.addPhone("Galaxy S24", "Samsung", 899.49, 7);
    inventory.addPhone("Pixel 9", "Google", 799.99, 5);

    inventory.showPhones();
    billing.sellPhone(inventory, 0, 2);
    billing.sellPhone(inventory, 2, 1);

    inventory.removePhone(1);
    inventory.updateStock("iPhone 15", 5);

    Report::exportReport(billing, inventory);
    Report::showSummary(billing, inventory);
}

Direfencias antes y despues de factorización

Antes (Espagueti) Después (SRP aplicado)
Una sola clase hacía todo (God Class) Se separan 3 clases con responsabilidades claras.
Mezcla de inventario y facturación Cada clase tiene un único motivo de cambio.
Dificultad para mantener y probar Código modular, fácil de extender o testear.
Duplicación de lógica y variables globales Encapsulación y métodos bien definidos.

Compilacion y ejecucion del codigo

image
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment