CODESAMPLE

Layered Architecture - C++

Share on:

The Layered Architecture pattern organizes an application into distinct horizontal layers, each performing a specific role. This promotes separation of concerns, making the system more maintainable and testable. Layers typically include a Presentation Layer (UI), a Business Logic Layer, and a Data Access Layer. Each layer only interacts with the layers immediately above and below it.

This C++ example demonstrates a simplified layered architecture for managing user accounts. The PresentationLayer handles user interaction, the BusinessLogicLayer contains account-related business rules (like validation), and the DataAccessLayer interacts with a simple in-memory database. The use of interfaces (IAccountRepository, IAccountService) is a common C++ practice for decoupling layers and allowing for easier dependency injection and testing. This approach is readily adaptable to more complex scenarios with real databases and applications.

#include <iostream>
#include <vector>
#include <string>
#include <algorithm>

// Data Access Layer
class IAccountRepository {
public:
  virtual bool saveAccount(const std::string& username, const std::string& password) = 0;
  virtual bool authenticateAccount(const std::string& username, const std::string& password) = 0;
  virtual ~IAccountRepository() = default;
};

class InMemoryAccountRepository : public IAccountRepository {
private:
  std::vector<std::pair<std::string, std::string>> accounts;
public:
  bool saveAccount(const std::string& username, const std::string& password) override {
    accounts.push_back({username, password});
    return true;
  }

  bool authenticateAccount(const std::string& username, const std::string& password) override {
    return std::any_of(accounts.begin(), accounts.end(), 
                       [&](const auto& account){ return account.first == username && account.second == password; });
  }
};

// Business Logic Layer
class IAccountService {
public:
  virtual bool registerAccount(const std::string& username, const std::string& password) = 0;
  virtual bool loginAccount(const std::string& username, const std::string& password) = 0;
  virtual ~IAccountService() = default;
};

class AccountService : public IAccountService {
private:
  IAccountRepository* repository;

public:
  AccountService(IAccountRepository* repo) : repository(repo) {}

  bool registerAccount(const std::string& username, const std::string& password) override {
    if (username.empty() || password.empty()) return false;
    return repository->saveAccount(username, password);
  }

  bool loginAccount(const std::string& username, const std::string& password) override {
    if (username.empty() || password.empty()) return false;
    return repository->authenticateAccount(username, password);
  }
};

// Presentation Layer
class PresentationLayer {
private:
  IAccountService* service;

public:
  PresentationLayer(IAccountService* svc) : service(svc) {}

  void run() {
    std::string username, password;
    char choice;

    do {
      std::cout << "\nMenu:\n";
      std::cout << "1. Register\n";
      std::cout << "2. Login\n";
      std::cout << "3. Exit\n";
      std::cout << "Enter your choice: ";
      std::cin >> choice;

      switch (choice) {
        case '1':
          std::cout << "Enter username: ";
          std::cin >> username;
          std::cout << "Enter password: ";
          std::cin >> password;
          if (service->registerAccount(username, password)) {
            std::cout << "Account registered successfully!\n";
          } else {
            std::cout << "Registration failed.\n";
          }
          break;
        case '2':
          std::cout << "Enter username: ";
          std::cin >> username;
          std::cout << "Enter password: ";
          std::cin >> password;
          if (service->loginAccount(username, password)) {
            std::cout << "Login successful!\n";
          } else {
            std::cout << "Login failed.\n";
          }
          break;
        case '3':
          std::cout << "Exiting...\n";
          break;
        default:
          std::cout << "Invalid choice. Try again.\n";
      }
    } while (choice != '3');
  }
};

int main() {
  InMemoryAccountRepository repository;
  AccountService service(&repository);
  PresentationLayer presentation(&service);

  presentation.run();

  return 0;
}