工厂模式在开发中应该算是使用的比较多了,比如做图形处理的时候,每种不同的图形需要不同的图形类去处理,这些图形类就可以继承一个图形的抽象类,实现handle方法;然后根据图形的类型,创造不同的图形类去处理不同的图形逻辑;
工厂模式属于“创建型”的设计模式,使用工厂来代替了new操作的模式;在实际使用的时候,又有几种不同的类型;下面来简单了解下:
1>简单静态工厂
举个例子,有个面条的抽象类,有一个描述的方法,如下
package com.example.springbootDemo.service.factory;
public abstract class INoodles {
/**
* 描述每种面条啥样的
*/
public abstract void desc();
}
然后我们分别定义三种具体的面条,分别如下
package com.example.springbootDemo.service.factory;
public class LzNoodles extends INoodles{
@Override
public void desc() {
System.out.println("兰州拉面 上海的好贵 家里才5 6块钱一碗");
}
}
public class PaoNoodles extends INoodles {
@Override
public void desc() {
System.out.println("泡面好吃 可不要贪杯");
}
}
public class GankouNoodles extends INoodles {
@Override
public void desc() {
System.out.println("还是家里的干扣面好吃 6块一碗");
}
}
之后我们定义一个工厂来生产面条
public class SimpleNoodlesFactory {
public static final int TYPE_LZ = 1;//兰州拉面
public static final int TYPE_PM = 2;//泡面
public static final int TYPE_GK = 3;//干扣面
public static INoodles createNoodles(int type) {
switch (type) {
case TYPE_LZ:
return new LzNoodles();
case TYPE_PM:
return new PaoNoodles();
case TYPE_GK:
default:
return new GankouNoodles();
}
}
}
调用的方法
public static void main(String[] args) {
INoodles noodles = SimpleNoodlesFactory.createNoodles(SimpleNoodlesFactory.TYPE_LZ);
noodles.desc();
}
这种方式就是简单静态工厂模式;其实跟new一个对象的区别就是延迟了对象的创建过程,或者说封装了对象的创建,把这个创建的过程放在一个单独的类里面根据类型创造出来,这个类就是工厂。
特点:1.该工厂是一个具体的类,有一个create的方法来生成对应的不同的产品(面条),根据类型(if/switch)来判断是哪种产品,new不同的产品类;
2.create是静态的,所以也可以称为静态工厂。
3.不方便的是如果要增加一种产品,那么就需要在工厂类里面添加一个判断,扩展性比较差;
4.不同的产品需要不同的参数的时候也是不支持的。
2>另外一种简单工厂(基于反射)
public class StaticNoodlesFactory {
/**
* 传入Class实例化面条产品类
*
* @param clz
* @param <T>
* @return
*/
public static <T extends INoodles> T createNoodles(Class<T> clz) {
T result = null;
try {
result = (T) Class.forName(clz.getName()).newInstance();
} catch (Exception e) {
e.printStackTrace();
}
return result;
}
}
在创建具体的产品类的时候,使用反射而不是具体的类型,这样增加或者减少产品时,就不用修改工厂类了;
调用方法
public static void main(String[] args) {
//兰州拉面
INoodles lz = StaticNoodlesFactory.createNoodles(LzNoodles.class);
lz.desc();
//泡面
INoodles pm = StaticNoodlesFactory.createNoodles(PaoNoodles.class);
pm.desc();
}
缺点:因为Class.forName(clz.getName()).newInstance()调用的是无参构造函数生成对象,它和new Object()是一样的性质,而工厂方法应该用于复杂对象的初始化 ,当需要调用有参的构造函数时便无能为力了,这样像为了工厂而工厂
3>普通工厂
普通工厂就是把简单工厂的创建过程拆分成一个一个的小工厂,比如生成兰州拉面的定义一个工厂,生产泡面的定义一个工厂;产品类做了抽象,创建过程也做了抽象;具体代码如下
定义一个抽象的生产面条的接口
public abstract class NoodlesFactory {
public abstract INoodles create();
}
生产干扣面的工厂
public class GankouFactory extends NoodlesFactory {
@Override
public INoodles create() {
return new GankouNoodles();
}
}
/**
* 兰州拉面的工厂
*/
public class LzFactory extends NoodlesFactory {
@Override
public INoodles create() {
return new LzNoodles();
}
}
/**
* 泡面的工厂
*/
public class PaoFactory extends NoodlesFactory {
@Override
public INoodles create() {
return new PaoNoodles();
}
}
使用的时候代码
public static void main(String[] args) {
NoodlesFactory noodlesFactory = new PaoFactory();
INoodles iNoodles = noodlesFactory.create();
iNoodles.desc();
}
普通工厂比简单工厂要复杂一些,每个对应的产品都有一个具体生产它的小工厂,在这个小工厂中,去创建对应的产品,这样的好处是需求变化的时候,不需要修改已有的类;拥抱变化;
4>多个产品的抽象工厂
上面介绍的都是单产品的,生产面条,了解下多产品系的,比如客栈,不仅买面条,还有喝的,面条有不同的面条,同样喝的也有不同的类型,可乐,橙汁,雪碧等等;这时候,我们可以抽象出一个饮料的类,然后不同店里面返回不同的饮料;通过一个例子说明;
public abstract class IDrinks {
/**
* 描述每种饮料多少钱
*/
public abstract void prices();
}
/**
* 可乐
*/
public class ColaDrinks extends IDrinks {
@Override
public void prices() {
System.out.println("可乐三块五");
}
}
/**
* 水
*/
public class WaterDrinks extends IDrinks {
@Override
public void prices() {
System.out.println("和我一样的穷鬼都喝水,不要钱~!");
}
}
然后我们定义饭店的抽象类,具体有吃面和喝水的功能,不同的店可以吃不同的面喝不同的水
/**
* 抽象的饭店工厂
*/
public abstract class AbstractFoodFactory {
/**
* 生产面条
*
* @return
*/
public abstract INoodles createNoodles();
/**
* 生产饮料
*/
public abstract IDrinks createDrinks();
}
/**
* KFC
*/
public class KFCFoodFactory extends AbstractFoodFactory {
@Override
public INoodles createNoodles() {
return new PaoNoodles();//KFC居然卖泡面
}
@Override
public IDrinks createDrinks() {
return new ColaDrinks();//卖可乐
}
}
/**
* 兰州拉面
*/
public class LzlmFoodFactory extends AbstractFoodFactory {
@Override
public INoodles createNoodles() {
return new LzNoodles();//卖兰州拉面
}
@Override
public IDrinks createDrinks() {
return new WaterDrinks();//卖水
}
}
工厂和产品都做了抽象,面向接口编程,拥抱变化;比如说兰州拉面馆卖可口可乐了,那就返回就好了
@Override
public IDrinks createDrinks() {
return new ColaDrinks();
}