简单工厂模式
说实话 每次学习设计模式都是开始于简单工厂模式,结束于工厂方法模式,主要是因为和工厂相关的模式有三种:简单工厂、工厂方法、抽象工厂 然后,然后就乱糟糟的了
其实细想,以前学习太浮躁的,只是看看资料不去深入思考,再再再次学习设计模式,决定要认真的学,每个设计模式都写一篇有关自己思考的博客。无关质量,只是想通过这种方式,加深自己的理解,也方便以后的学习中查缺补漏,或审视自己的不足。
简单工厂模式要素
首先是要弄清楚我学习的这个模式的用处,顾名思义,就是可以和简单的通过工厂类来生成对象,在这里可以将生成的对象统一称为(抽象称为)产品。而简单工厂的目的是在工厂类中,我们只需要通过传入参数(标记)就能得到相对应的产品对象。因此简单工厂这个模式的要素总结为以下3点:
- 抽象产品 负责描述具体产品所包含的公共行为接口,是所有具体产品的父类;
- 具体产品 实现抽象产品的接口,具体的描述自身的行为;
- 简单工厂 提供生成产品的静态方法,具体业务中,通过调用该简单工厂的生成产品的静态方法,即可获得相应的对象;
具体实现
简单工厂实现起来也十分方便,按照上述简单工厂的要素逐一编程实现:
第一步:声明抽象产品的接口
package com.shine.study.designpatterns.simplefactory.onetest; /** * @Author: Shine EtherealWind * @Description: 抽象产品的接口 声明了产品所包含的共有的行为方法; * @Date: create in 9:34 2022/3/9 */ public interface IProduct { void show(); }
第二步:若干个具体产品类 简单工厂类将通过不同标识获得不同的具体产品类的对象
//第一个具体产品 package com.shine.study.designpatterns.simplefactory.onetest; /** * @Description: 具体产品1 实现了产品共同接口 * @Date: create in 9:34 2022/3/9 */ public class Product1 implements IProduct { @Override public void show() { System.out.println("这是产品1"); } } //第二个具体产品 package com.shine.study.designpatterns.simplefactory.onetest; /** * @Description: * @Date: create in 9:35 2022/3/9 */ public class Product2 implements IProduct { @Override public void show() { System.out.println("这是产品2"); } } //默认的具体产品 package com.shine.study.designpatterns.simplefactory.onetest; /** * @Description: * @Date: create in 9:36 2022/3/9 */ public class ProductDefault implements IProduct { @Override public void show() { System.out.println("这是默认产品"); } }
第三步:核心的简单工厂类
package com.shine.study.designpatterns.simplefactory.onetest; /** * @Author: Shine EtherealWind * @Description: * @Date: create in 9:37 2022/3/9 */ public class SimpleFactory { public static IProduct getProduct(String mark){ IProduct pro = null; switch (mark){ case "1" : pro = new Product1(); break; case "2" : pro = new Product2(); break; default : pro = new ProductDefault(); } return pro; } }
测试:
class TestMain{ public static void main(String[] args) { System.out.println("测试生产产品1"); IProduct pro = SimpleFactory.getProduct("1"); pro.show(); } }
运行结果:
分析:
简单工厂方法就是通过提供静态方法,通过传入的参数来获得相对应的具体对象。简单说下优缺点
优点:
- 用户在获取对象的时候不需要关心怎么去构造对象,只需传入对应的具体产品的标识即可;
- 工厂类和产品类职责单一只需负责各自的工作;
缺点:
- 可以看出每次新增一个具体产品的时候,都需要修改简单工厂的静态方法,可以看出代码间的耦合度太高,不符合“开闭原则 ” ;
- 随着具体产品越来越多,将会导致工厂类很烦杂,工厂类一旦出错,所有的产品将不能获取;
面向接口编程
写到这里,还想补充记录说明下面向接口编程
在上述的工厂类的获取对象的静态方法实现和测试的时候有以下的代码出现:
IProduct pro = null; pro = new Product1(); break;
IProduct pro = SimpleFactory.getProduct("1");
以前看到类似这样的代码总是不禁疑惑,为什么非要用接口的引用去指向一个具体对象呢?为什么不同对象本身类去声明引用呢?
其实这里就是面向接口编程的体现,我们知道jvm中对象的创建都是在堆上开辟出空间,里面放生成的对象的,而IProduct pro = null;这种只是在内存中声明一个引用,最终它指向的是一个具体对象的地址。
这样写的话 这个pro只能使用接口中提供的公共方法,而无法使用具体类中的自己的方法,如下例子:
通过接口申明的引用指向具体的地址时候,我们是无法访问到对象的独有的成员方法的
那么我们要怎么访问到呢?
通过这种向下强转 可以做到访问对象的独有的方法的;
那么为什么要用接口引用指向实现类的对象?
这种写法其实Java多态的表现形式(一个接口类型的引用变量来引用实现接口的类的实例,当这个引用调用方法时,它会根据实际引用的类的实例来判断具体调用哪个方法)
多态的定义:指允许不同类的对象对同一消息做出响应。即同一消息可以根据发送对象的不同而采用多种不同的行为方式。(发送消息就是函数调用)
为什么一般都使用 接口引用指向子类对象 ,而不用 实现类本身 引用呢?
问题就在于接口可以有多个实现类,如果现在你使用这个实现类接收,也许哪一天你需要换成其它的实现类呢?
这时你只要将new的实现类对象换成你想要的就行了, 其它地方的代码根本不需要改动。
注意事项
没有在接口定义的方法(实现类增加的方法)是不可以被访问到的
在接口的实现类中该实现方法的类型和参数必须与接口中所定义的精确匹配。