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. oracle数据库字符集查询

    1>数据库服务器字符集 select * from nls_database_parameters,其来源于props$,是表示数据库的字符集. 查询结果如下 NLS_LANGUAGE AMER ...

  2. iframe 加载外部资源,显示隐藏loading,onload失效

    在项目中使用iframe 来加载外部资源,需要在iframe请求外部资源的时候,需要显示一个loading,在加载完成后,将这个loading隐藏掉,刚开始看到W3C中 iframe有一个 onloa ...

  3. mysql sql注入getshell新姿势

     sql.php?sql=1'报错信息为:1064:You have an error in your SQL syntax; check the manual that corresponds to ...

  4. php验证18位身份证,准到必须输入正确的身份证号,

    /** * 验证18位身份证(计算方式在百度百科有) * @param string $id 身份证 * return boolean */ function check_identity($id=' ...

  5. python 三方面库整理

    测试开发 Web UI测试自动化 splinter - web UI测试工具,基于selnium封装. selenium - web UI自动化测试. –推荐 mechanize- Python中有状 ...

  6. PHP(javascript基础)

    js浏览器的脚本语言js的基础语法和 . js Dom操作写法分类1.行内(内联)写在标签里面,以属性的形式表现,属性名是“事件属性名” 例如:<button onClick="js代 ...

  7. shell 脚本的编写

    创建一个shell文件 1. 创建一个.sh文件 2. 文件第一行声明shell编译器路径  #!/bin/bash 3. 修改文件权限 chmod 777 文件名    或  /bin/bash  ...

  8. 使用jsonp请求本地json文件

    使用jsonp解决请求本地文件跨域问题 <!DOCTYPE html> <html lang="en"> <head> <meta cha ...

  9. 图->最短路径->单源最短路径(迪杰斯特拉算法Dijkstra)

    文字描述 引言:如下图一个交通系统,从A城到B城,有些旅客可能关心途中中转次数最少的路线,有些旅客更关心的是节省交通费用,而对于司机,里程和速度则是更感兴趣的信息.上面这些问题,都可以转化为求图中,两 ...

  10. NodeJS笔记(二)- 修改模块默认保存路径

    参考:nodejs prefix(全局)和cache(缓存)windows下设置 假设nodejs根目录为“D:\nodejs” 如下所示,新建“node_cache”文件夹用来存放全局缓存 该路径下 ...