tortelee

导航

< 2025年2月 >
26 27 28 29 30 31 1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28 1
2 3 4 5 6 7 8
 

How Layers Should Be Realized

The matter of how layers should be realized is determined by the client-server nature of the relationship between an application and its platform/virtual machine. This includes some characteristics of layers discussed previously:

  • Asymmetry:

    • Interactions between a virtual machine and its application layer should be initiated exclusively by action of the application.
    • (Note, however, that this applies only to steady-state operation, since there may be cases during system start up, shut down, or failure recovery, where the virtual machine may need to initiate the action.)
  • Interface-based interactions:

    • All interactions between applications and a layer should occur via the interface of the layer.
    • This interface should provide services that are well-suited for implementing applications that encompass its domain.
    • Furthermore, the interface should be stable even if the implementation of the virtual machine might be subject to change.
  • Domain-specific services grouping:

    • The set of services realized by a virtual machine should be selected based on the domain or domains of the applications it is intended to support.

To illustrate how applications use the interface of a layer to achieve specific goals, let's consider a few examples across different domains. These examples will demonstrate how applications interact with a layer's interface to utilize its services, ensuring that all interactions are encapsulated within the layer's interface.

Example 1: Database Access Layer

Scenario

An application needs to perform CRUD (Create, Read, Update, Delete) operations on a database. The database access layer provides an interface for these operations.

Database Access Layer Interface

class IDatabase {
public:
    virtual ~IDatabase() = default;
    virtual void connect(const std::string& connectionString) = 0;
    virtual void disconnect() = 0;
    virtual void executeQuery(const std::string& query) = 0;
    virtual std::vector<std::string> fetchResults() = 0;
};

Implementation of Database Access Layer

class MySQLDatabase : public IDatabase {
public:
    void connect(const std::string& connectionString) override {
        // Implementation for connecting to MySQL database
    }

    void disconnect() override {
        // Implementation for disconnecting from MySQL database
    }

    void executeQuery(const std::string& query) override {
        // Implementation for executing a query on MySQL database
    }

    std::vector<std::string> fetchResults() override {
        // Implementation for fetching results from MySQL database
        return {};
    }
};

Application Using the Database Access Layer

class Application {
public:
    Application(IDatabase* db) : database(db) {}

    void run() {
        database->connect("connection_string");
        database->executeQuery("SELECT * FROM users");
        auto results = database->fetchResults();
        for (const auto& result : results) {
            std::cout << result << std::endl;
        }
        database->disconnect();
    }

private:
    IDatabase* database;
};

int main() {
    MySQLDatabase db;
    Application app(&db);
    app.run();
    return 0;
}

Example 2: Logging Layer

Scenario

An application needs to log messages for debugging and auditing purposes. The logging layer provides an interface for logging messages.

Logging Layer Interface

class ILogger {
public:
    virtual ~ILogger() = default;
    virtual void logInfo(const std::string& message) = 0;
    virtual void logWarning(const std::string& message) = 0;
    virtual void logError(const std::string& message) = 0;
};

Implementation of Logging Layer

class ConsoleLogger : public ILogger {
public:
    void logInfo(const std::string& message) override {
        std::cout << "[INFO] " << message << std::endl;
    }

    void logWarning(const std::string& message) override {
        std::cout << "[WARNING] " << message << std::endl;
    }

    void logError(const std::string& message) override {
        std::cout << "[ERROR] " << message << std::endl;
    }
};

Application Using the Logging Layer

class Application {
public:
    Application(ILogger* logger) : logger(logger) {}

    void run() {
        logger->logInfo("Application started");
        // Perform some operations
        logger->logWarning("This is a warning message");
        // Perform some more operations
        logger->logError("This is an error message");
        logger->logInfo("Application finished");
    }

private:
    ILogger* logger;
};

int main() {
    ConsoleLogger logger;
    Application app(&logger);
    app.run();
    return 0;
}

Example 3: Network Communication Layer

Scenario

An application needs to send and receive data over the network. The network communication layer provides an interface for network operations.

Network Communication Layer Interface

class INetwork {
public:
    virtual ~INetwork() = default;
    virtual void connect(const std::string& address, int port) = 0;
    virtual void disconnect() = 0;
    virtual void sendData(const std::string& data) = 0;
    virtual std::string receiveData() = 0;
};

Implementation of Network Communication Layer

class TCPNetwork : public INetwork {
public:
    void connect(const std::string& address, int port) override {
        // Implementation for connecting to a TCP server
    }

    void disconnect() override {
        // Implementation for disconnecting from a TCP server
    }

    void sendData(const std::string& data) override {
        // Implementation for sending data over TCP
    }

    std::string receiveData() override {
        // Implementation for receiving data over TCP
        return {};
    }
};

Application Using the Network Communication Layer

class Application {
public:
    Application(INetwork* network) : network(network) {}

    void run() {
        network->connect("127.0.0.1", 8080);
        network->sendData("Hello, Server!");
        auto response = network->receiveData();
        std::cout << "Received: " << response << std::endl;
        network->disconnect();
    }

private:
    INetwork* network;
};

int main() {
    TCPNetwork network;
    Application app(&network);
    app.run();
    return 0;
}

Summary

In these examples, the application interacts with different layers (database access, logging, network communication) through well-defined interfaces. These interfaces provide the necessary services for the application to achieve its goals. The implementation details of each layer are hidden behind the interface, ensuring that the application remains stable even if the underlying implementation changes. This approach promotes modularity, maintainability, and flexibility in software design.

posted on   tortelee  阅读(1)  评论(1编辑  收藏  举报
相关博文:
阅读排行:
· 本地部署 DeepSeek:小白也能轻松搞定!
· 传国玉玺易主,ai.com竟然跳转到国产AI
· 自己如何在本地电脑从零搭建DeepSeek!手把手教学,快来看看! (建议收藏)
· 我们是如何解决abp身上的几个痛点
· 如何基于DeepSeek开展AI项目
 
点击右上角即可分享
微信分享提示