Java学习打卡:第二十四天
内容导航
Java养成计划(打卡第24天)
内容管理
实例拓展分析
我们昨天所构建的项目实例中使用了singleton pattern 还有 strategy pattern ,这我们是可以发现的,就是我们创建一个对象就要使用单一实例模式,就是要将构造方法私有化,创建一个建立一个对象的类方法,这里直接由对象不空判断边界;实现多种数据库连接就要使用strategy pattern,我们创建Dao接口,对于不同的数据库使用不同的实现类。
那这里还有一个疑问:为什么要创建一个DaoFactory类?虽然我们知道它的功能就是根据文件生成一个指定的类的对象(properties),那如果自己在操作过程中很有可能就直接将获取对象的操作放到service类里面去了?
其实我们这里的设计是有依据的,就像我们看到只要一个对象就使用单一实例,这里的依据就是设计模式中的工厂模式----factory pattern
factory pattern
说到factory当然就是生产product了,那在Java世界里的factory当然也是起到生产的作用,只是这里的产品就是我们(客观世界实体抽象出的软件模型)对象了,为什么会用工厂创建对象,而不直接new呢 生产对象
应用场景
-
创建对象非常复杂,不知道创建哪种类型的对象(上转型,多态)------昨天实例情况,不知道该创建Oracle还是MySOL,并且创建这个对象需要用到Properties和文件IO,比较复杂
-
需要创建很多对象(同一类), 如果用户直接创建会做大量的重复劳动,java要极力避免代码的重复
-
系统不应该依赖对象创建的细节,为实现灵活迁移,不输入类的功能,service类是提供逻辑服务的,创建对象的操作不属于service的操作
factory标准定义和作用
工厂模式是一个用于创建对象的接口,让子类决定实例化哪一个类,工厂方法使一个类的实例化延迟到其子类
- 【待创建对象抽象为一个接口】
屏蔽对象创造的复杂性(被封装了)
- 【工厂抽象为接口】
解耦,上层应用不需要关心具体的待创建对象,只会使用接口,简单可以不抽象,复杂的就要创建子类工厂----昨天实例中的Dao接口
- 【工厂的抽象结构随待创建对象的复杂程度不同而不同】
扩展性更好,增加代创建对象的类型或层次,只要增加相应的工厂和对象类型就好
factory pattern的多种实现方式
工厂按照类型有多种实现方式,首先就是简单工厂--------将类型抽象成方法–>多方法单类工厂(工厂方法模式)------将对象类型抽象为类----->多方法多类工厂(抽象工厂模式) 扩展工厂
简单工厂 simple factory
昨天的例子就是简单工厂,简单工厂的要点有
- 产品类面向接口/抽象类设计 ------就是产品设计成一个接口,这个产品接口有几个具体实现的子产品类比如昨天的Dao接口和实现类OracleDao和MySOLDao
- 一个工厂方法生产所有的产品,---------昨天的DaoFactory的getInstance()方法中根据File生成所有的子产品类
- Client端只需要了解工厂和抽象的产品类,调用时只需要调用接口来实现
simple pattern的缺点
- 不符合开闭规则,修改时,如添加一个新产品就需要修改整个工厂类
模式模型
产品接口Dao ---------两个具体的子产品实现类MySOLDao ,,OracleDao
生产这两种产品的都是DaoFactory中的getInstance方法
(小知识:接口中的方法不必加abstract修饰,普通抽象类中需要)(但是这里的方法也有更先进的地方,那就是使用配置文件,所以我们修改产品就直接修改文件就好了)这里的产品对象的产生是由文件决定,非常适合迁移
其实总结来说工厂就是创建对象的,昨天的实例里面我们也是根据配置文件产生一个对象,所以就非常方便,在实际开发中要灵活使用文件IO和反射
那我们用基础简单工厂的方式来创建一下对象试试(项目背景查看昨日博客)
Dao d = DaoFactory.getFactory().getInstance("MySQLDao");
//使用代工厂创建对象,尤其是多态
public class DaoFactory {
private static DaoFactory factory = null;//工厂只有一个,只能创建一个对象
private DaoFactory(){//无参方法不要忘记加括号
}
public static DaoFactory getFactory(){
if(factory == null)
{
factory = new DaoFactory();
}
return factory;
}
public Dao getInstance(String name)
{
if(name.equalsIgnoreCase("OracleDao"))
{
return new OracleDao();
}
else return new MySQLDao();
}
}
这就是不加文件,我们在这里如果要进行数据库迁移,还是会一个一个进入该名字,这里我们创建对象是通过的字符串的比较,相比文件的字节码就要低级很多了。
多方法单类工厂(工厂方法模式) Factory method(一对一)
工厂方法的要点
- 产品类和工厂类都面向接口、抽象类设计
- 一种产品只对应一个工厂类(每个工厂类只生产一种产品)
- Client端只需要了解工厂和抽象的产品类
缺点
容易引起类操作
这个的核心其实就是将工厂的规模扩大,并且让工厂专精,将总工厂设置为接口或抽象类,让一个工厂去实现一个产品
这里我们还是以上面的例子来实现模拟Method Factory
//我们将DaoFactory设置成一个接口,让MySQLDaoFactory和OracleDaoFactory实现implements接口
//在OracleDaoFactory中我们只创建Oracle对象
public class OracleDaoFactory {
public Dao getInstance(String name){
return new OracleDao();
}
//在service类中
DaoFactory factory = new OracleDaoFactory();//其实也可以使用单一实例模式直接调用类方法创建对象
Dao = factory.insatance();
多方法多类工厂(抽象工厂模式) Abstract factory(一对多)
实现的要点
- 产品类和工厂类面向接口、抽象类设计
- 一种产品对应一个工厂类
- 一个工厂类生产多个级别的产品
- Client端只了解工厂和抽象类
缺点
扩展产品困难,需要修改所有的工厂类
这种工厂就是实现大规模的产品操作了,首先产品还是抽象的,但是每个子实现类产品又有几个类别,比如我们的OracleDao假如分成两种子产品,分为OracleBusinessDao和OracleStudyDao;MySQL同理,那么我们创建工厂还是建立一个抽象的工厂接口,然后两个具体的实现类工厂,但是分类依据不同了
分为BusinessDaoFactory和StudyDaoFactory, 像BusinessDaoFactory就要同时生产多个类的产品了比如OracleBusinessDao以及MySQLBusinessDao
个人经验
总的来说我们一般需要创建不知道类别的对象的时候就要使用工厂模式,这样我们的Service类就会简洁一些,同时要减少使用简单工厂,一但产品类型过多就会让整个代码非常长并且我们一旦修改整个类都要变动,不利于操作,就使用Strategy模式设计接口,但是这种不依赖文件IO的工厂模式修改还是不方便,所以我个人建议是我们直接使用昨天的Java反射机制调取文件,设计成简单工厂就解决问题了,并且还非常易于修改文件,变动项目
好了,我们今天的分享就结束了,如果有任何的疑问欢迎咨询~~