为什么使用工厂模式?
1、new对象的细节我不想关心,我只想使用该对象。
2、当一个对象的构造方法需要多个以上的参数的时候,这个就比较麻烦了。
3、当一个对象是第三方jar包提供的,在构建该对象时,我不知道应该传哪些构造参数或者搞明白这些构造参数很费劲,比如说BasicDataSource类
使用工厂模式创建的对象要不是就是一大堆(每个都不同),要不就是一大批(每个都相同)
工厂生产的一般不是数据对象,都是业务对象 (Student---数据对象 UserService---业务对象)
优缺点
优点:
很明显,简单工厂的特点就是“简单粗暴”,通过一个含参的工厂方法,我们可以实例化任何产品类,上至飞机火箭,下至土豆面条,无所不能。所以简单工厂有一个别名:上帝类。
缺点:
任何”东西“的子类都可以被生产,负担太重。当所要生产产品种类非常多时,工厂方法的代码量可能会很庞大。
在遵循开闭原则(对拓展开放,对修改关闭)的条件下,简单工厂对于增加新的产品,无能为力。因为增加新产品只能通过修改工厂方法来实现。
工厂方法正好可以解决简单工厂的这两个缺点。
spring中是通过配置文件和反射解决了简单工厂中的缺点。
工厂设计模式相关概念:
1、产品:类
2、抽象产品:抽象类,接口
3、产品簇
4、产品等级
学习设计模式,脑袋里要时刻蹦两根弦:
A:开发代码的程序猿,被划分为两种角色
作者(服务器端程序猿)
用户(客户端程序猿)
比如,我们使用C3p0时,我们拿着别人写好的数据库连接池的字节码在使用,制作c3p0的程序猿就是作者。
B:我们手头并不会是时刻都拥有作者的源代码的,比如在使用c3p0时,我们能用,但是我们找不到c3p0的源码文件(*.Java),此时就算我们想篡改c3p0的源代码,都找不着。就算我们有c3p0的源代码,也不能改,因为要符合开闭原则。
简单工厂示例
package com.wang.h_simplefactory.a;
//抽象产品
interface Food{
void eat();
}
//具体产品
class Hamburger implements Food{
public void eat() {
System.out.println("吃汉堡包");
}
}
// ===============================================================
public class AppTest {
public static void main(String[] args) {
Food f= new Hamburger();
f.eat();
}
}
缺点:这种设计相当脆弱: 为什么?因为,只要作者修改了具体产品的类名,那么客户端代码,也要随之一起修改。
这样服务器代码和客户端代码就是耦合的。
我们希望的效果是,无论服务器代码如何修改,客户端代码都应该不知道,不用修改客户端代码
package com.wang.h_simplefactory.b;
// 针对a包中的问题,服务器代码一旦修改,客户端代码也要跟着修改。
// 作者修改代码如下:使用简单工厂设计模式。
//抽象产品
interface Food {
void eat();
}
// 具体产品
class Hamburger implements Food {
public void eat() {
System.out.println("吃汉堡包");
}
}
class RiceNoodle implements Food {
public void eat() {
System.out.println("吃过桥米线");
}
}
class FoodFactory {
public static Food getFood(int n) {
Food food = null;
switch (n) {
case 1:
food = new Hamburger();
break;
case 2:
food = new RiceNoodle();
break;
default:
break;
}
return food;
}
}
// ===============================================================
class LP implements Food{
public void eat() {
System.out.println("三秦套餐 - 吃凉皮");
}
}
public class AppTest {
public static void main(String[] args) {
Food f = FoodFactory.getFood(1);
f.eat();
}
}
/**
* 接口要趋向于稳定,
* 设计模式中的接口,不单指interface,只要是下层给上层暴露的方法,都叫接口。一个公共方法,或者类,只要暴露出去,都是接口。
* 简单工厂
* 优点:
* 1、把具体产品的类型,从客户端解耦出来
* 2、服务器端,如果修改了具体产品的类名,客户端也不知道,这符合了面向接口编程思想。
*
* 缺点:
* 1、客户端必须自己去记具体常量与产品之间的映射关系。
* 2、如果具体产品特别多,则简单工厂,就会变得十分臃肿。比如100个产品,则switch中就有100个case。
* 3、最重要的是,变化来了,客户端需要扩展新的产品。则用户势必要修改简单工厂的代码,这样便违反的开闭原则。
*/
简单工厂UML例图
知识备注:
c3p0是什么?
c3p0是一个库,c3p0.jar。它扩展了传统的jdbc数据库连接池,并且支持JDBC3规范和JDBC2的标准扩展。
c3p0是一种jdbc数据库连接池。
那么为什么使用数据库连接池呢?
因为数据库连接是一种关键的、有限的、昂贵的资源。
传统的模式(如传统的java web项目中,servlet的beans中建立数据库连接),每次连接都需要验证用户,消耗了大量的时间和资源。而数据库连接池在系统初始化的时候,将数据库连接作为对象存储在内存中,当用户需要访问数据库时,并非建立一个新的连接,而是从连接池中取出一个已经建立的空闲连接对象。使用完毕后,用户不关闭连接,而是将数据库连接对象放回连接池中。数据库连接池管理数据连接的建立、断开,同时监视数据库连接数量和使用情况。使用数据库连接池会显著提高整个应用程序的伸缩性(大大提高了连接数量)和健壮性(能够应对大量用户频繁连接数据库,减少系统资源的消耗),提高应用程序的性能指标。