一、概念
1. 关注点分离:对象生命周期的管理应该独立于其领域的业务逻辑之外;
2. 依赖注入(DI):将组件与其需要的服务分离,这样组件就不必知道这些服务的名称,也不必知道如何获取它们。
【解释】客户端对象需要的独立的服务对象是由外部提供的。客户端对象不需要关心它所需要的服务对象本身,或者主动请求服务对象。
方式:1. 通过构造函数注入
2. 通过setter注入
3. 通过小类大对象中的多态继承的方式注入
3. 依赖倒置(DIP):解耦技术
4. 单例:类似于全局变量
缺点:1、对单例对象的依赖都藏于代码中,通过类的接口无法知道依赖关系
2、测试时无法被替身替代,不利于测试
3、需求的变化,可能导致依赖单例的类都需要被修改
二、实现
不好的实现:单例模式
//单例模式
class Logger final
{
public:
static Logger& getInstance()
{
static Logger& theLogger{};
return theLogger;
}
void writeInfoEntry(std::string_view entry)
{
//...
}
void writeWarnEntry(std::string_view entry)
{
//...
}
void writeErrorEntry(std::string_view entry)
{
//...
}
};
// ======================================================
class Customer
{
};
class CustomerRepository
{
public:
Customer findCustomerById(const int id)
{
Logger::getInstance().writeInfoEntry("log.....");
//...
}
};
优化:解决强依赖问题,依赖倒置原则
#include <memory>
#include <string_view>
#include <iostream>
//接口
class LoggingFacility
{
public:
virtual ~LoggingFacility() = default;
virtual void writeInfoEntry(std::string_view entry) = 0;
virtual void writeWarnEntry(std::string_view entry) = 0;
virtual void writeErrorEntry(std::string_view entry) = 0;
};
using Logger = std::shared_ptr<LoggingFacility>;
//实现
class StandardOutputLogger : public LoggingFacility
{
virtual void writeInfoEntry(std::string_view entry) override
{
std::cout << "[INFO] " << entry << std::endl;
}
virtual void writeWarnEntry(std::string_view entry) override
{
std::cout << "[WARNING] " << entry << std::endl;
}
virtual void writeErrorEntry(std::string_view entry) override
{
std::cout << "[ERROR] " << entry << std::endl;
}
};
class Customer
{
//...
};
class CustomerRepository
{
public:
CustomerRepository() = delete;
explicit CustomerRepository(const Logger& loggingService) : logger(loggingService) // 依赖于接口
{}
Customer findCustomerById(const int id)
{
logger->writeInfoEntry("log.....");
//...
}
private:
Logger logger;
};
UML图