【问题标题】:Dependency injection vs abstract class vs inheritance vs singleton依赖注入 vs 抽象类 vs 继承 vs 单例
【发布时间】:2016-01-12 20:48:55
【问题描述】:

我有三个班级:

  • Logger 将进程信息记录到文件中
  • 验证输入数据的Checker
  • Operations 对输入数据执行操作。

我需要在 Checker 和 Operations 中都使用 Logger 来输出(记录)该过程。 我需要操作中的检查器,以检查数据的有效性。

class Logger {

}

class Checker {
  // inherit Logger ?
  // dependency-inject Logger ?
  // access Logger statically ?
  // compose Logger as singleton or create new object ?
}

class Operations {
  // inherit Logger ?
  // dependency-inject Logger ?
  // access Logger statically ?
  // compose Logger as singleton or create new object ?
}

应用程序将只创建一个 Operations 和 Checker 类的实例。问题是 - 在不需要或创建新对象的情况下,Logger 应该是什么类型的类以及它应该如何在 Operations 和 Checker 类中实现?

【问题讨论】:

    标签: php oop


    【解决方案1】:

    如果您正在对接口进行编程,那么最灵活的选择是使用装饰器:

    interface ILogger
    {
        function log($msg);
    }
    class FileLogger implements ILogger{
        function log($msg)
        {
            file_put_contents('file.dat', $msg . "\n", FILE_APPEND);
        }
    }
    
    
    interface IChecker
    {
        function check($var);
    }
    class Checker implements IChecker {
        function check($var)
        {
            //do some checking
            return true;
        }
    }
    //decorator
    class LoggingChecker implements IChecker
    {
        private $checker;
        private $logger;
        function __construct(IChecker $checker, ILogger $logger)
        {
            $this->checker = $checker;
            $this->logger = $logger;
        }
    
        function check($var)
        {
            $checkResult = $this->checker->check($var);
            $this->logger->log('check result is: ' . ($checkResult)? 'a success' : 'a failure');
            return $checkResult;
        }
    }
    
    
    interface IOperations
    {
        function doOperation($var);
    }
    class Operations implements IOperations{
        private $checker;
    
        function __construct(IChecker $checker)
        {
            $this->checker = $checker;
        }
    
        function doOperation($var)
        {
            if($this->checker->check($var)){
                //do some operation
            }
         }
    }
    
    //composotion root
    //create concrete logger, in this case a FileLogger instance, though you could latter create a SqlLogger or EmailLogger 
    //and swap it without any changes to the other classes
    $logger = new FileLogger();
    //create concreate checker
    $checker = new Checker();
    //create decorated checker
    $loggingChecker = new LoggingChecker($checker, $logger);
    //Operations can now be instantiated with either the regular checker, or the decorated logging checker, and it will
    //work just the same, with no knowledge of the existense of loging, or indeed any knowledge of how the checker functions, beyond
    //the fact it has a method called check that excepts a single parameter
    
    $operation = new Operations($checker); //no logging is done
    //OR
    $operation = new Operations($loggingChecker); //logging is done
    

    请注意,在上面的示例中,我只为IChecker 创建了一个装饰器。

    您还可以为IOperations 创建一个装饰器,例如LoggingOperations,其工作方式相同——它依赖于ILoggerIOperations 的实例。 您将使用相同的具体 ILogger 实现 ($logger) 和 IOperations 实现 ($operation) 来实例化它。

    使用该对象的类对IOperations 具有单一依赖关系,可以使用$operation$logginOperation 进行实例化,并且行为方式相同。

    希望这个示例让您了解接口编程的灵活性以及装饰器模式如何简化依赖类并帮助实施 SRP

    【讨论】:

      【解决方案2】:

      直接回答你的问题,logger应该是什么样的类...

      真正单例的一个典型例子是日志服务。假设我们 有一个基于事件的日志服务:客户端对象请求该文本 通过向日志记录服务发送消息来记录。其他对象 通过侦听在某处(控制台、文件等)实际记录文本 到这些日志记录请求的日志记录服务并处理它们。 首先,请注意日志服务通过了经典测试 单身:

      请求者需要一个众所周知的对象来向其发送请求 日志。这意味着一个全球访问点。由于日志服务是 多个侦听器可以注册的单个事件源,有 只需要一个实例。

      更多信息在这里Why we should consider the «Logger» class as a singleton?

      对于一个不错的记录器,如果你的框架中没有一个,你应该看看这个klogger

      【讨论】:

        【解决方案3】:

        这取决于,是否有可能拥有具有不同属性的记录器对象? (例如,将日志写入其他文件夹或根据其属性对要记录的消息执行不同的操作)如果是这样,则依赖注入是一种方式。

        记录器的执行方式是否相同,甚至不需要属性? (例如,它只是将 msg 写入相对于源文件夹的预定义文件)。你甚至不需要使用单例,它可能是一个带有静态方法的实用程序类。

        最后,如果您的记录器需要初始化并且您只初始化一次,那么您可以使用单例。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2012-09-23
          • 2019-05-06
          • 1970-01-01
          • 2014-10-09
          • 1970-01-01
          • 2020-12-10
          • 1970-01-01
          • 2016-11-09
          相关资源
          最近更新 更多