作为一名oop程序员,设计原则是必须知道的知识:单一职责,开闭原则,依赖倒置,接口隔离,替换法则。
在看【Head First】一书时,突然对依赖倒置有了一些简单的理解。
先看依赖倒置的定义:要依赖抽象,不要依赖具体类。
其意思是具体类要依赖抽象,抽象不应该依赖具体类,更扩展一点就是说具体类也尽量不要依赖具体类。
首先,何为具体类,我的理解,具体类应该就是某个具体的对象,是对现实中的实物或其他的一种反应,即就是类的实例,具体代码上就是通过new出来的对象。
比如Object obj = new Object();这样便产生了一个具体对象。而若是直接在一个对象中new另一个对象,则这两个对象依赖在了一起,增加了这个类的耦合性。
让我们先回到依赖倒置上!这个倒是有点像面向接口编程,但是这里更强调的“抽象”,这种抽象可以是一个接口,也可以是一个抽象类。这个原则说明了:不能让
“高层组件”依赖“低层组件”,而且两者都应该依赖于抽象。
我来举一个例子。如果我们要开一家奶茶店,那我们首先想到的是什么呢,肯定是想到在什么地方开奶茶店,要多少员工,然后才是卖什么奶茶。
没错,我们的思考方法一般都是从顶端 开始,然后往下才是具体类。但是要开奶茶店又要想怎么生产奶茶,这是一件很要命的事情。对于一个奶茶店主来说,并不
想理会奶茶这写具体类,否则奶茶店将全部依赖这些奶茶具体类。这时候就要倒置我们的思想,先从低端开始,从奶茶开始,抽象出一个奶茶抽象。
这时候“奶茶店”就是“高层组件”,各种奶茶就是“低层组件”。由于奶茶店是如果买奶茶的具体类,则奶茶店对全部奶茶有了依赖,高层组件与低层有了依赖关系。
这个模式告诉我们:我们应该依赖抽象类,而不应该具体类,无论是高层组件还是低层组件都应该如此。
那么我们就想到定义一个奶茶的抽象类型,即为所有的奶茶提供一个抽象,而奶茶店则只需要面对这个抽象,而不用去管这个抽象的具体类是什么。即奶茶店只需
要专注于卖奶茶,收钱找钱什么的,而不用管具体奶茶是什么。这样奶茶店就依赖于奶茶的抽象,而不是依赖奶茶的具体类。
class TeaShop{ public void sell(){ Tea tea = new SimpleTea(); tea.produce(); } }
这样虽然我们创建了一个抽象,但我们 仍在代码中,实际的创建的具体类(SimpleTea),所以,这样的抽象并不能实现低耦合。
这时候,可以使用工厂模式来对代码进行进一步重构,来创建一个TeaFactory;为了使这个工厂更具有扩展型,我们来对工厂进行抽象。
public class abstract TeaFactory{ public Tea makeTea(String type){ createTea(type).produce(); } public abstract Tea createTea(String tea); }
这时候我们在郑州开了个奶茶店,则创建一个郑州奶茶工厂。
public class ZZTeaFactory extends TeaFacory{ public Tea createTea(String tea){ if(tea.equles("simple")){ return new SimpleTea(); }else{ return new OtherTea(); } } }
这样就实现了一个奶茶的工厂模式。那么通过奶茶店进行点选奶茶的时候:
class TeaShop{ public void sell(){ TeaFactory factory = new ZZTeaFactory(); Tea tea = factory.makeTea("simple"); } }
我们通过工厂模式将奶茶店与奶茶进行解耦,而且通过工厂模式也大大提高了程序的可扩展型,比如我们如果要在洛阳也开一家奶茶店的话,但是洛阳奶茶店所卖的
奶茶与郑州的奶茶并不一样,这时候我们只要实现一个洛阳的奶茶工厂,实现奶茶工厂的抽象即可,实现了开闭原则。通过这种将实例化延迟到子类中进行的方式。
在次回到依赖倒置上,为什么使用工厂模式就实现了依赖倒置了呢?
首先我们画一下类图:
这时候高层组件(TeaShop)和低层组件(SimpleTea,OtherTea)都依赖于Tea抽象。想要遵循依赖倒置原则,工厂方法并非是唯一的方法,但却是
最有效的方法。
如何避免违反依赖倒置原则:
1.变量不可以持有具体类的引用。(持有类的引用即通过new出来的对象)
2.不要让类派生自具体类。(如果派生自具体类,就产生了依赖,请派生自一个抽象)
3.不要覆盖基类中已实现的方法。
但是如果随时都要遵循这个原则,是不可能的,因为我们如果不new一个对象,那么我们是什么都写不成的。所以这个原则也有适用行。如果有一个不像是会改变
的类,则具体类一点问题都没有的。而常改变的 类则可以使用一些技巧。
永远不变的是变化本身,我们使用设计原则,设计模式,则是为了更好的应对变化,封装变化。
参考资料:《Head First 设计模式》