Explicit Dependencies Principle

The Explicit Dependencies Principle states:

Methods and classes should explicitly require (typically through method parameters or constructor parameters) any collaborating objects they need in order to function correctly.

If your classes require other classes to perform their operations, these other classes are dependencies.

These dependencies are implicit if they exist only in the code within your class, and not in its public interface.

Explicit dependencies appear most often in an object’s constructor, for class-level dependencies, or in a particular method’s parameter list, for more local dependencies.

Classes with implicit dependencies  cost more to maintain than those with explicit dependencies.

  • They are more difficult to test because they are more tightly coupled to their collaborators.
  • They are more difficult to analyze for side effects, because the entire class’s codebase must be searched for object instantiations or calls to static methods.
  • They are more brittle and more tightly coupled to their collaborators, resulting in more rigid and brittle designs.

Classes with explicit dependencies are more honest.

  • They state very clearly what they require in order to perform their particular function.
  • They tend to follow the Principle of Least Surprise by not affecting parts of the application they didn’t explicitly demonstrate they needed to affect.
  • Explicit dependencies can easily be swapped out with other implementations, whether in production or during testing or debugging. This makes them much easier to maintain and far more open to change.

The Explicit Dependencies Principle is closely related to the Dependency Inversion Principle and the Hollywood Principle.

Consider the PersonalizedResponse class in this Gist, which can be constructed without any dependencies:

Implicit Dependencies Example

This class is clearly tightly coupled to the file system and the system clock, as well as a particular customer instance via the global Context class.  If we were to refactor this class to make its dependencies explicit, it might look something like this:

 

namespace ImplicitDependencies
{
class Program
{
static void Main(string[] args)
{
var customer = new Customer()
{
FavoriteColor = "Blue",
Title = "Mr.",
Fullname = "Steve Smith"
};
Context.CurrentCustomer = customer; var response = new PersonalizedResponse(); Console.WriteLine(response.GetResponse());
Console.ReadLine();
}
} public static class Context
{
public static Customer CurrentCustomer { get; set; } public static void Log(string message)
{
using (StreamWriter logFile = new StreamWriter(
Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments),
"logfile.txt")))
{
logFile.WriteLine(message);
}
}
} public class Customer
{
public string FavoriteColor { get; set; }
public string Title { get; set; }
public string Fullname { get; set; }
} public class PersonalizedResponse
{
public string GetResponse()
{
Context.Log("Generating personalized response.");//a particular Log instance via the global Context class
string formatString = "Good {0}, {1} {2}! Would you like a {3} widget today?";
string timeOfDay = "afternoon";
if (DateTime.Now.Hour < 12)// the system clock
{
timeOfDay = "morning";
}
if (DateTime.Now.Hour > 17)
{
timeOfDay = "evening";
}
return String.Format(formatString, timeOfDay,
Context.CurrentCustomer.Title, //a particular customer instance via the global Context class
Context.CurrentCustomer.Fullname,
Context.CurrentCustomer.FavoriteColor);
}
}
}

  

  

Explicit Dependencies Example

In this case, the logging and time dependencies have been pulled into constructor parameters, while the customer being acted upon has been pulled into a method parameter.

The end result is code that can only be used when the things it needs have been provided for it (and whether you scope dependencies at the class or method level will depend on how they’re used by the class, how many methods reference the item in question, etc. – both options are shown here even though in this case everything could simply have been provided as method parameters).

using System;
using System.IO;
using System.Linq; namespace ExplicitDependencies
{
class Program
{
static void Main(string[] args)
{
var customer = new Customer()
{
FavoriteColor = "Blue",
Title = "Mr.",
Fullname = "Steve Smith"
}; var response = new PersonalizedResponse(new SimpleFileLogger(), new SystemDateTime());//class constructor Console.WriteLine(response.GetResponse(customer));//method parameters
Console.ReadLine();
}
} public interface ILogger
{
void Log(string message);
} public class SimpleFileLogger : ILogger
{
public void Log(string message)
{
using (StreamWriter logFile = new StreamWriter(
Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments),
"logfile.txt")))
{
logFile.WriteLine(message);
}
}
} public interface IDateTime
{
DateTime Now { get; }
} public class SystemDateTime : IDateTime
{
public DateTime Now
{
get
{
return DateTime.Now;
}
}
} public class Customer
{
public string FavoriteColor { get; set; }
public string Title { get; set; }
public string Fullname { get; set; }
} public class PersonalizedResponse
{
private readonly ILogger _logger; private readonly IDateTime _dateTime; public PersonalizedResponse(ILogger logger,
IDateTime dateTime)//class constructor
{
this._dateTime = dateTime;
this._logger = logger;
} public string GetResponse(Customer customer)//method parameters
{
_logger.Log("Generating personalized response.");
string formatString = "Good {0}, {1} {2}! Would you like a {3} widget today?";
string timeOfDay = "afternoon";
if (_dateTime.Now.Hour < 12)
{
timeOfDay = "morning";
}
if (_dateTime.Now.Hour > 17)
{
timeOfDay = "evening";
}
return String.Format(formatString, timeOfDay,
customer.Title,
customer.Fullname,
customer.FavoriteColor);
}
}
}

  

See Also

//a particular customer instance via the global Context class

编码原则 之 Explicit Dependencies Principle的更多相关文章

  1. 编码原则 之 Stable Dependencies

    The Stable Dependencies Principle states that “The dependencies between software packages should be ...

  2. S.O.L.I.D 是面向对象设计(OOD)和面向对象编程(OOP)中的几个重要编码原则

    注:以下图片均来自<如何向妻子解释OOD>译文链接:http://www.cnblogs.com/niyw/archive/2011/01/25/1940603.html      < ...

  3. 开放封闭原则(Open Closed Principle)

    在面向对象的设计中有很多流行的思想,比如说 "所有的成员变量都应该设置为私有(Private)","要避免使用全局变量(Global Variables)",& ...

  4. 最少知识原则(Least Knowledge Principle)

    最少知识原则(Least Knowledge Principle),或者称迪米特法则(Law of Demeter),是一种面向对象程序设计的指导原则,它描述了一种保持代码松耦合的策略.其可简单的归纳 ...

  5. 接口分离原则(Interface Segregation Principle)

    接口分离原则(Interface Segregation Principle)用于处理胖接口(fat interface)所带来的问题.如果类的接口定义暴露了过多的行为,则说明这个类的接口定义内聚程度 ...

  6. 依赖倒置原则(Dependency Inversion Principle)

    很多软件工程师都多少在处理 "Bad Design"时有一些痛苦的经历.如果发现这些 "Bad Design" 的始作俑者就是我们自己时,那感觉就更糟糕了.那么 ...

  7. 里氏替换原则(Liskov Substitution Principle)

    开放封闭原则(Open Closed Principle)是构建可维护性和可重用性代码的基础.它强调设计良好的代码可以不通过修改而扩展,新的功能通过添加新的代码来实现,而不需要更改已有的可工作的代码. ...

  8. 单一职责原则(Single Responsibility Principle)

    单一职责原则(SRP:The Single Responsibility Principle) 一个类应该有且只有一个变化的原因. There should never be more than on ...

  9. 【设计原则和编程技巧】单一职责原则 (Single Responsibility Principle, SRP)

    单一职责原则 (Single Responsibility Principle, SRP) 单一职责原则在设计模式中常被定义为“一个类应该只有一个发生变化的原因”,若我们有两个动机去改写一个方法,那这 ...

随机推荐

  1. mybatis07--关联查询一对多

    案例   查询国家的同时,查询出国家下的省会信息! 01.使用单表的连接查询 创建对应的实体类 和数据库表 /** * *国家的实体类 */ public class Country { privat ...

  2. 七牛 qshell 全命令实践

    七牛API服务的命名行测试工具,参考文档 七牛开发者中心 命令行工具(qshell) 实践目的 安装 account 设置ak.sk stat 查看文件状态 buckets/listbucket/do ...

  3. HTML、CSS知识点,面试开发都会需要--No.6 设置背景

    No.6 设置背景 1.background (1)如何设置背景:背景可通过color.image.gradient渐变或者组合方法设置. (2)background-color:颜色格式可以是十六进 ...

  4. php直接执行linux 命令

    注意你可以使用的命令只能是php这个用户组的权限和范围,注意这个linux 执行的,windows也是可以对应dos命令,但是打印格式不是很好看 //$output = `ls -al`; //$ou ...

  5. vivado/FPGA 使用小纪

    1.使用FPGA做为外部控制器的总线译码时,将总线时钟接在全局时钟脚上(MRCC),就算接在了局部时钟(SRCC)上,也要通过BUFG转为全局时钟走线,否则会因为local clk到各部分的时延较大引 ...

  6. RabbitMQ的几个概念

    VHost:虚拟主机,不同的VHost之间完全隔离,互不干扰.类似我们使用VM创建的多个虚拟机.创建好VHost之后需要我们指定其所有者.创建方式:RabbitMQ管理控制台 - Admin → Vi ...

  7. 磁盘异步I / O在Windows上显示为同步

    概要 Microsoft Windows上的文件I / O可以是同步或异步的.I / O的默认行为是同步的,其中调用I / O函数并在I / O完成时返回.异步I / O允许I / O函数立即将执行返 ...

  8. 洛谷P3455 ZAP-Queries [POI2007] 莫比乌斯反演+数论分块

    正解:莫比乌斯反演 解题报告: 传送门! 首先这题刚看到就很,莫比乌斯反演嘛,和我前面写了题解的那个一模一样的,所以这儿就不讲这前边的做法辣QAQ 但是这样儿还有个问题,就现在已知我每次都是要O(n) ...

  9. 002-自定义打开terminal,以及快捷键,其他程序类似,ssh管理-sshpass, Shuttle

    一.利用Automator软件完成服务设定 1.使用Command+Space,打开Spotlight,搜索Automator 2.搜索到之后,双击打开,选择“服务[或快速操作]” 3.将“服务收到[ ...

  10. python基础(15)-socket网络编程&socketserver

    socket 参数及方法说明 初始化参数 sk = socket.socket(参数1,参数2,参数3) 参数1:地址簇 socket.AF_INET IPv4(默认) socket.AF_INET6 ...