分析工厂方法模式和抽象工厂模式
代码下载见置顶篇文章,下载java23中设计模式的具体实现[下载地址][1]。
工厂设计模式的作用:
起初在我们创建对象的时候都是直接new。这样做有一个弊端,就是当后期有改动 需要跟换一个对象的时候,就需要改动特别大,程序中对该对象进行引用的地方都需要进行改动。因为代码的耦合性太大了,不利于后期维护。
不仅仅是创建对象时候的是这样,其实方法中也是这样,java的面向对象的封装和分派告诉我们,一个方法中有很长的一段代码,这样的代码其实并不好,不仅代码难看,而且这么长的代码 如果中间有某个东西需要改动,可能就会引起这个方法中的所有代码进行改动,并且代码太长,导致结果不清晰,更改工作也会变得非常困难,一样是耦合性太大。为了避免这种东西,所以把很长的一段代码进行分离,切割成一段一段,这样段与段之间的耦合性减小,更改某一段的代码 并不会影响其他的代码。
所以成熟的java代码一定要做到的高内聚、低耦合。
高内聚:代码与代码之间的联系是非常密切的。
低耦合:虽然联系密切,但是代码调用另一段代码的方式可以不直接进行调用(比如通过工厂)。
工厂模式的发展:
为了减小代码之间的耦合性,所以在类中进行A a = new A();的时候一定要考虑一下这里可不可以通过工厂来创建A对象。
1、工厂模式是基于接口的,通常为了达到类中A a= new A();同一个方法,后期A对象中的这个方法既要保留,又要对A中的方法进行改造,这时候我们不得不用B对象来处理原先的业务,我们就需要改成B b = new B(); 然后把之前程序中对a的引用都改成b对象。
2、如果刚开始我们就有一种面向接口的思想,用接口进行子类方法的调用,比如说A对象实现了接口Father,在类中进行调用的时候我们用接口调用指向实现类,Father father = new A(); 这种方式如果后期需要对具体是实现方法进行改造,又要保留A中的方法实现,这时我们就可以通过创建一个新的B对象,重写接口中的方法,然后把代码改为Father father = new B();其余的东西都不需要改动即可。这样就增强了我们代码的可扩展性。
3.但是通过接口调用子类的时候会发现,其实耦合性还是挺高的,我们还是要对源程序中进行更改,需要把A对象变成B对象。需要对java源代码进行重新编译,然后发布。这样就有可能造成代码更新发布的时候出现失误,导致业务逻辑出现问题等。为了解决这个问题,我们引入了工厂。也就是说源程序中的对象创建不是直接进行创建的,而是把创建对象这件事情交给工厂去做。比如Father father = BeanFactory.createBean(“BeanName”);通过调用工厂中的一个方法返回一个接口的实现类。这样,如果我们后期要对对象进行更换,则不需要更改这个类中的任何代码,只需要对工厂中具体的方法实现进行更改即可。
这样改造之后就很好的体现了java的封装思想,代码中不设计到Father的具体子类,减少了错误修改的次数。
4.但是我们还会发现一个问题,就是代码和工厂之间还是具有一定耦合性,比如说我后期要换一个工厂来创建对象,还是要更改源程序,不利于维护。这时候就出现了IOC,也是Spring的核心思想,控制反转,意思就是把创建对象的权利交给Spring(工厂) ,可以理解为Spring就是一个大的工厂,集成了Spring就说明整个项目中只有这一个大工厂,业务中所有的对象都可以交给Spring来进行创建。也就省去了后期要更换工厂的忧虑。并且Spring通过注解或者xml配置文件的方式进行对象的依赖注入(DI),使得对象的创建工作也变得非常简单。
java单继承,多实现。所以一般用接口。
其中工厂模式中包括几个部分:
1.简单工厂(返回值为对象的具体类型):
就是简单的创建一个工厂类,用于创建具体的对象。
2.工厂方法模式(返回值为抽象对象类型):
工厂中产出来的对象是一个抽象的对象,它可以有很多子类。具体返回哪个子类需要根据逻辑进行判断。(比如一个车辆的牌子有很多,工厂方法就提供逻辑进行判断具体返回哪一个牌子的具体车型。)
不论是简单工厂还是工厂方法都有以下两种方式创建工厂:
1.静态工厂:生产对象的方法为静态方法。可以通过类名直接进行调用。Factory.createBean();
2.普通工厂:生产对象的方法不是静态方法。先创建工厂对象,然后通过对象调用方法。
Factory factory = new Factory();
factory.createBean();
工厂方法模式代码展示:
产品接口
具体产品1
具体产品2
工厂方法
业务层面通过工厂创建对象
但是随着业务的发展,产品种类的增多,这时候需要更换一个工厂对象来创建对象。把原先的Factroy factory = new Factory();改成NewFactoru newFactory = new NewFactroy();为了满足这种需求,使代码能够承受这种改变,这时候引入了抽象工厂的模式。意思是不仅仅对具体的产品进行抽象化,对工厂对象也进行抽象,减小代码与工厂之间的耦合性。
3.抽象工厂:
对工厂进行抽象,一个抽象工厂类可以有多个具体工厂类,用于生产不同的对象。抽象工厂和工厂方法之间的最大区别就是抽象工厂所生产的对象更加复杂了。传统的抽象方法一般只用于生产一种产品(同一个产品接口),而抽象工厂则是用于生成多种产品,比如生产车的工厂,生产飞机的工厂,就可以用一个抽象工厂来表示。
肯定有人会有疑问,为什么不把他们用两个工厂来生产呢,现实开发时,一般确实是不同的产品用不同的工厂来进行生产,但是如果这两个工厂之间有一定的联系,比如生产汽车和生产飞机的工厂都要早轮胎,这时为了两个工厂通用同一段代码,则把这两个工厂提取出一个抽象工厂。每个具体的工厂类负责创建一类产品的实例。(如:汽车的的牌子有很多,奔驰宝马等。抽象工厂就是用一个具体的工厂来生产每一种类型的车,比如一个越野工厂类,只生产各种牌子的越野车。私家车工厂,生产各种产品的私家车。)
抽象工厂代码展示
思路整理:
在具体的开发中,要怎么用工厂模式要根据实际情况进行判断。像开头所说的,为了后期代码的扩展性更高一点,我们一般都要使用工厂方法模式,因为这样工厂所产生的是一个抽象的对象,当业务需求改变,我们只需要改变工厂中产生的对象即可。而当要生产的对象比较复杂,产品种类过多(比如车可以分为奔驰 宝马 奥迪等,但是每一个分类又可以分为越野车,商务车等),这些产品不属于同一个种类,但是有一定的联系,这时候可以考虑抽象工厂,把工厂进行具体的分类。每个具体的工厂负责不同种类的产品生产,这样就会使工厂的结构才会更加清晰。
抽象工厂模式的区别就是创建的对象更加复杂。
[1]: