这是否违反了“依赖倒置原则”?
public class Connection {
public Connection(){
}
public String description() {
return "Generic";
}
}
public class SqlServerConnection extends Connection{
public SqlServerConnection(){
}
public String description(){
return "SQL Server";
}
}
public class OracleConnection extends Connection{
public OracleConnection(){
}
public String description(){
return "Oracle";
}
}
public class MySqlConnection extends Connection{
public MySqlConnection(){
}
public String description(){
return "MySQL";
}
}
public class FirstFactory {
String type;
public FirstFactory(String t){
type = t;
}
public Connection createConnection(){
if(type.equals("Oracle")){
return new OracleConnection();
}else if(type.equals("SQL Server")){
return new SqlServerConnection();
}else{
return new MySqlConnection();
}
}
}
public class TestConnection {
public static void main(String[] args) {
FirstFactory factory;
factory = new FirstFactory("Oracle");
Connection connection = factory.createConnection(); //createConnection return concrete implementation not an abstraction
System.out.println("You're connection with " + connection.description());
}
}
这是来自VTC设计模式的视频教程我的问题是这个例子违反了依赖倒置原则吗?
因为TestConnection类依赖于具体的实现,因为factory.createConnection()返回的具体实现不是抽象。
我可以通过这样做来解决这个问题吗?
public Connection createConnection(){
Connection connection = null;
if(type.equals("Oracle")){
connection = new OracleConnection();
}else if(type.equals("SQL Server")){
connection = new SqlServerConnection();
}else{
connection = new MySqlServerConnection();
}
return connection;
}
理想情况下,您可以将工厂注入到TestConnection中(即通过接口将一个ConnectionFactory作为参数),而不是调用“new”来获得工厂。 这样TestConnection不依赖于Factory或Connection的具体实现。
工厂返回Connection的具体实现很好 - 事实上,如果你想实际使用连接,这是必要的。 您不依赖于特定的具体实现,因为工厂将其作为Connection(即作为接口)返回。 有人在某处确实需要实例化Connection实现 - 这是Factory的工作。
如果OracleConnection具有其他连接没有的某些方法,并且调用类取决于这些方法,那将是一种违规行为。 这里不是这种情况。
虽然可以说您的通用架构并不是实现数据库连接的最佳方式,但我会跳过这一点,因为我理解的问题是关于依赖倒置而不是数据库实现。 要实现完全依赖性倒转:
Connection
应该是一个接口,而不是一个具体的类。 ConnectionFactory
应该是一个接口,而不是一个具体的类,它定义了一个返回Connection
的createConnection()
方法。 它的构造函数中不需要参数。 ConnectionFactory
的不同具体类,并返回实现Connection
对象。 上面的内容更好地满足了依赖倒置原则,因为现在TestConnection只是指定了它从服务提供者所需要的内容,并没有与任何具体的实现耦合。 任何具体的实现都可以被创建和使用,只要它满足为TestConnection定义的接口指定的要求,并且接口指定的不过是TestConnection真正需要的。
特别是,另一个包中的另一个供应商可以创建一个新的Factory
和Connection
实现,并且可以将其插入代码中(如果您遵循上述体系结构),并且您的TestConnection
类不需要任何修改。
这支持许多具体服务与服务客户的运行时关联的范例。 例如,在一个典型的启动时依赖注入场景中,你会将一个具体的ConnectionFactory
实现注入到TestConnection
,然后它看起来像:
public class TestConnection {
private ConnectionFactory connectionFactory;
public setConnectionFactory(ConnectionFactory connectionFactory) {
this.connectionFactory = connectionFactory;
}
public static void main(String[] args) {
//
// Perform dependency injection here
//
// after dependency injection
Connection connection = connectionFactory.createConnection(); //createConnection return concrete implementation not an abstraction
System.out.println("You're connection with " + connection.description());
}
}
这将TestConnection完全从任何数据库的依赖关系中分离出来,并且通过注入一个ConnectionFactory
可以轻松配置它。 或者,也可以不执行“执行依赖注入”,而是执行服务查找。 J2EE / J3EE广泛使用它,例如从JNDI Context
对象中获取ConnectionFactory(或更典型的是一个DataSource
)。 这些超出了问题的范围,只是作为您想要这样做的一个例子,以及一种检查您是否满足该原则的方法。 对于来自外部资源(如数据库驱动程序)的任何内容, TestConnection
只应该引用Interfaces而不是Classes。
依赖倒置原则的原则是
A - 高级模块不应该依赖于低级模块。 两者都应该依赖于抽象。
在你的情况下,你已经有了抽象的连接,这是很好的。 在我看来,工厂模式的使用也很好。
B - 抽象不应该取决于细节。 细节应该取决于抽象。
你的连接不依赖于较低的实现,并且继承的类可能使用Connection的方法/变量(如果这个例子可能更复杂)
顺便说一句,我会倾向于使Connection成为一个抽象类,如果您稍后要添加更多的功能,并且不打扰为您制作的默认构造函数
public class Connection {
public abstract String description();
}
或者只是让它成为一个界面
public interface Connection {
String description();
}
链接地址: http://www.djcxy.com/p/82239.html
上一篇: Does this violate the "Dependency Inversion Principle"?
下一篇: Service Locator, Dependency Injection (and Container) and Inversion of Control