解决依赖与多种模式的应用
《秘封活动记录·祝》到了,Gogo很开心的去吃土了。
读了不少关于设计模式的书,一直不知道如何应用,最近构思 ForeverNight 时,才真正尝试用模式去解决问题,接下来是我关于一些模式、方法,在解决依赖方面的感悟。
什么是依赖?
我对依赖的理解比较简单,若 A类需要用到 B类实例的一些方法,那么 A就依赖 B,本文是一只萌新的感悟,在定义并不严谨,请路过的大佬包涵。
单例模式
用单例模式来解决依赖是比较容易的。
但我并不喜欢单例,因为它有许多缺点。单例很像全局变量,大量单例会让程序更加复杂,并且带来耦合问题。而且许多情况下,单例并不能很好的解决问题,比如无法动态提供一个子类的示例来代替。
1 | /** |
服务定位模式
服务定位模式是专门创建一个类,用于提供服务。服务定位模式会有静态的方法或静态的实例来提供服务。
它与单例模式有许多相似之处,都是通过静态获取依赖,只不过服务定位模式提供的是其他类的实例,而单例模式提供的是它本身的实例。
相比单例模式,服务定位模式有一些优势,它将提供服务的职责与服务的实现分离,更符合单一职责原则;它能动态地提供服务。对于一些全局的服务使用服务定位模式而非单单例模式更合适。
1 | /** |
然而对于非全局、不唯一的对象,服务定位模式并非那么有用。并且由于服务定位模式也是依赖于静态,大量使量会造成类似单例的代码混乱。
依赖注入
相对于服务定位模式中,使用者主动获取依赖,另一种常见的获取依赖的方式,是由外部把依赖传递过来,这就是依赖注入。
依赖注入,最常见的就是通过构造函数注入依赖,比如下面这个例子。
1 | /** |
另外一种是通过Setter函数注入依赖,这就不示范了。
依赖注入,可以很好地解决前面几个模式的一些问题,由于依赖的创建、获取都是外界负责的,这就把获取依赖的职责分离。
当然这也会造成麻烦,比如上面这个例子,创建对象的过程变得繁琐,需要先准备好依赖才能创建。为了将这个复杂的过程封装起来,还得使用工厂模式,我想为何Java中工厂模式这么常见,其中一大原因就是依赖注入导致对象的创建过程变得复杂吧。
IoC容器
虽然依赖注入可以解决依赖的问题,但遇到一些复杂的依赖仍是比较崩溃。
比如 A依赖于 B和 C, B和 C又有各自的依赖。即使把整个过程放入工厂中,也是令人十分头疼。
这时使用IoC容器便是一个选择,IoC容器在解决这类复杂的依赖时极为有用。可以把IoC容器理解为一张注册表,只要向这之中注册依赖,以后就可以获取。
比如上述的例子,只要先把 B和 C所需的依赖注册,那么创建 B和 C时,就可以通过容器获取所需的依赖。创建后再把 B和 C也注册到容器中,这样创建 A时就可以直接从 IoC容器中获取 B、C。若还有别的类依赖于 A呢?那就把 A也放入IoC中。
如此一来,工厂也会变得十分简单,只要从容器中获取依赖,再注入到 A之中即可。
若不是用容器,工厂会变得怎么样呢?若 B、C可以在工厂中创建,那么还好,创建即可。若 B、C是已经创建好的服务,不应该在 A的工厂中产生新的实例,那工厂又应该如何获取 B、C呢。
你会发现依赖注入仅仅是把 A的依赖转移到 A的工厂中,对工厂如何获取依赖,并没有什么贡献,还得用先前的模式解决。
有了 IoC容器情况就会大不相同,工厂只需要依赖容器就可以获取所需的所有依赖,那样大可以通过构造函数把容器注入到工厂中,就可以彻底摆脱前几种方式对静态的依赖。
1 | /** |