工厂方法模式:
定义:
定义一个用于创建对象的接口,让子类决定实例化哪一个类。工厂方法使一个类的实例化延迟到其子类。
解决的使项目中的实例化问题,一般我们是在某个地方用到某个类就new一个。工厂模式解决的是大量的实例化某些、某种、某批类的对象。
类图:
通用代码:
抽象产品类:
package com.test.Test;
public abstract class Product {
// 产品类的公共方法
public void method1() {
// 业务逻辑处理
}
// 抽象方法
public abstract void method2();
}
具体产品类:
具体产品类可以有多个,都继承于抽象产品类。
package com.test.Test;
public class ConcreteProduct1 extends Product {
public void method2() {
// 业务逻辑处理
}
}
package com.test.Test;
public class ConcreteProduct2 extends Product {
public void method2() {
// 业务逻辑处理
}
}
抽象工厂类:
抽象工厂类负责定义产品对象的产生。
package com.test.Test;
public abstract class Creator {
/*
* 创建一个产品对象,其输入参数类型可以自行设置
*
* 通常为String、Enum、Class等,当然也可以为空
*/
public abstract Product createProduct(Class<? extends Product> c);
}
具体工厂类:
具体如何产生一个产品的对象,是由具体的工厂类实现的。
package com.test.Test;
public class ConcreteCreator extends Creator {
public Product createProduct(Class<? extends Product> c) {
Product product = null;
try {
product = (Product) Class.forName(c.getName()).newInstance();
} catch (Exception e) {
// 异常处理
}
return product;
}
}
场景类:
package com.test.Test;
public class Client {
public static void main(String[] args) {
Creator creator = new ConcreteCreator();
Product product = creator.createProduct(ConcreteProduct1.class);
/*
* 继续业务处理
*/
}
}
例子:
抽象产品类:
package com.test.teaAndmilk;
/**
* 奶茶(抽象产品类)
* 2015年9月18日 下午5:19:01
* @author 张耀晖
*
*/
public abstract class TeaAndMilk {
//奶茶类的抽象方法,由具体的子类来实现
public abstract void prepare();
//奶茶类的公共方法
public void doWater(){
System.out.println("加入水。。。");
}
public void doMix(){
System.out.println("搅拌均匀。。。");
}
public void doCapping(){
System.out.println("封装加盖。。。完成");
}
}
具体产品类:
package com.test.teaAndmilk;
/**
* 绿茶(具体产品类)
* 2015年9月18日 下午5:34:17
* @author 张耀晖
*
*/
public class GreenTea extends TeaAndMilk {
@Override
public void prepare() {
System.out.println("加入绿茶所用的茶叶。。。");
}
}
package com.test.teaAndmilk;
/**
* 珍珠奶茶(具体产品类)
* 2015年9月18日 下午5:34:42
* @author 张耀晖
*
*/
public class GemMilk extends TeaAndMilk {
@Override
public void prepare() {
System.out.println("加入珍珠奶茶需要的材料。。。");
}
}
抽象工厂类:
package com.test.Factory;
import com.test.teaAndmilk.TeaAndMilk;
/**
* 抽象奶茶创建工厂(抽象工厂类)
* 2015年9月18日 下午5:34:08
* @author 张耀晖
*
*/
public abstract class FactoryCreator {
public abstract <T extends TeaAndMilk> T createTeaAndMilk(Class<T> c);
}
具体工厂类:
package com.test.Factory;
import com.test.teaAndmilk.TeaAndMilk;
/**
* 奶茶创建工厂(具体工厂类)
* 2015年9月18日 下午5:38:14
* @author 张耀晖
*
*/
public class TeaAndMilkFactory extends FactoryCreator{
@Override
public <T extends TeaAndMilk> T createTeaAndMilk(Class<T> c) {
TeaAndMilk teaAndmilk = null;
try {
teaAndmilk = (TeaAndMilk) Class.forName(c.getName()).newInstance();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
return (T)teaAndmilk;
}
}
场景类:
package com.test.client;
import com.test.Factory.FactoryCreator;
import com.test.Factory.TeaAndMilkFactory;
import com.test.teaAndmilk.GreenTea;
import com.test.teaAndmilk.TeaAndMilk;
/**
* 奶茶店(场景类)
* 2015年9月18日 下午5:46:05
* @author 张耀晖
*
*/
public class Client {
public static void main(String[] args) {
FactoryCreator creator = new TeaAndMilkFactory();
//如果顾客需要绿茶
TeaAndMilk teaAndmilk = creator.createTeaAndMilk(GreenTea.class);
//具体的业务处理
teaAndmilk.prepare();
teaAndmilk.doWater();
teaAndmilk.doMix();
teaAndmilk.doCapping();
}
}
运行结果:
工厂方法模式的优点:
大家应该能够深刻体会到工厂方法模式的好处:如果使用JDBC连接数据库,数据库从MySql切换到Oracle,需要改动地方就是切换一下驱动名称(前提条件是SQL语句是标准语句),其他的都不需要修改,这是工厂方法模式灵活性的一个直接案例。
工厂方法模式的使用场景:
工厂方法模式是new一个对象的替代品,所以在所有需要生成对象的地方都可以使用,但是需要慎重的考虑是否要增加一个工厂类来进行管理,增加代码的复杂度。
工厂方法模式的扩展:
缩小为简单工厂模式:
简单工厂模式:定义一个创建对象的类,由这个类来实例化对象的行为。
上例更改为简单工厂模式:
简单工厂模式中的工厂类:
package com.test.easyFactory;
import com.test.teaAndmilk.TeaAndMilk;
/**
* 奶茶创建工厂(简单工厂模式中的工厂)
* 2015年9月18日 下午7:12:51
* @author 张耀晖
*
*/
public class EasyFactory {
public static <T extends TeaAndMilk> T createTeaAndMilk(Class<T> c){
//定义一个生产出的奶茶种类
TeaAndMilk teaAndMilk = null;
try {
teaAndMilk = (TeaAndMilk)Class.forName(c.getName()).newInstance();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
return (T)teaAndMilk;
}
}
简单工厂模式中的场景类:
package com.test.easyFactory;
import com.test.teaAndmilk.GemMilk;
import com.test.teaAndmilk.TeaAndMilk;
/**
* 奶茶店(场景类)
* 2015年9月18日 下午7:21:00
* @author 张耀晖
*
*/
public class Client {
public static void main(String[] args) {
TeaAndMilk teaAndMilk = EasyFactory.createTeaAndMilk(GemMilk.class);
teaAndMilk.prepare();
teaAndMilk.doWater();
teaAndMilk.doMix();
teaAndMilk.doCapping();
}
}
运行结果:
分析与工厂方法模式的不同之处:
- 将工厂方法模式中的抽象工厂类(FactoryCreator类)去掉了
- 将具体工厂类(TeaAndMilkFactory类)中的createTeaAndMilk()方法设置为静态方法。简化了类的创建过程。并且去掉了继承抽象类。
- 因为工厂类发生类变化,所以会导致调用者场景类(Client类)发生类变化。
抽象工厂模式
定义:
为创建一组相关或相互依赖的对象提供一个接口,而且无须指定它们的具体类。
通用类图:
通用源码类图:
AbstractProductA和AbstractProductB两个抽象产品类可以有关系,例如共同继承一个抽象类或接口。
通用源码:
抽象产品类:
package com.test.Test;
public abstract class AbstractProductA {
// 每个产品共有的方法
public void shareMethod() {
}
// 每个产品相同方法,不同实现
public abstract void doSomething();
}
两个具体的产品实现类
产品A1的实现类:
package com.test.Test;
public class ProductA1 extends AbstractProductA {
@Override
public void doSomething() {
System.out.println("产品A1的实现方法");
}
}
产品A2的实现类:
package com.test.Test;
public class ProductA2 extends AbstractProductA {
@Override
public void doSomething() {
System.out.println("产品A2的实现方法");
}
}
产品B与此类似,代码省略了。
抽象工厂类:
抽象工厂类AbstractCreator的职责是定义每个工厂要实现的功能
该抽象工厂类定义了两个产品族的产品创建。
注意: 有N个产品族,在抽象工厂类中就应该有N个创建方法。
package com.test.Test;
public abstract class AbstractCreator {
// 创建A产品家族
public abstract AbstractProductA createProductA();
// 创建B产品家族
public abstract AbstractProductB createProductB();
}
产品等级1的实现类:
如何创建一个产品,则是有具体的实现类来完成的。
注意: 有M个产品等级就应该有M个实现工厂类,在每个实现工厂中,实现不同产品族的生产任务。
package com.test.Test;
public class Creator1 extends AbstractCreator {
// 只生产产品等级为1的A产品
public AbstractProductA createProductA() {
return new ProductA1();
}
// 只生产产品等级为1的B产品
public AbstractProductB createProductB() {
return new ProductB1();
}
}
产品等级2的实现类:
package com.test.Test;
public class Creator2 extends AbstractCreator {
// 只生产产品等级为2的A产品
public AbstractProductA createProductA() {
return new ProductA2();
}
// 只生产产品等级为2的B产品
public AbstractProductB createProductB() {
return new ProductB2();
}
}
场景类:
package com.test.Test;
public class Client {
public static void main(String[] args) {
// 定义出两个工厂
AbstractCreator creator1 = new Creator1();
AbstractCreator creator2 = new Creator2();
// 产生A1对象
AbstractProductA a1 = creator1.createProductA();
// 产生A2对象
AbstractProductA a2 = creator2.createProductA();
// 产生B1对象
AbstractProductB b1 = creator1.createProductB();
// 产生B2对象
AbstractProductB b2 = creator2.createProductB();
/*
*
*
*
* 然后在这里就可以为所欲为了...
*/
}
}
具体的应用实例:
人种接口:
package com.test.human;
/**
* 人种接口
* 2015年9月18日 下午8:50:17
* @author 张耀晖
*
*/
public interface Human {
// 每个人种都有相应的颜色
public void getColor();
// 人类都会说话
public void talk();
// 每个人都有性别
public void getSex();
}
人种有三个抽象类,负责人种的抽象属性定义:肤色和语言,白色人种、黑色人种、黄色人种
白色人种:
package com.test.human;
/**
* 白色人种
* 2015年9月18日 下午8:53:22
* @author 张耀晖
*
*/
public abstract class AbstractWhiteHuman implements Human {
@Override
//白色人种的皮肤颜色为白色
public void getColor() {
System.out.println("白色人种的皮肤颜色为白色!");
}
@Override
//白色人种讲话
public void talk() {
System.out.println("白色人种会说话,一般说的都是单字节!");
}
}
黄色人种:
package com.test.human;
/**
* 黄色人种
* 2015年9月18日 下午8:55:34
* @author 张耀晖
*
*/
public abstract class AbstractYellowHuman implements Human {
@Override
//黄色人种的皮肤颜色为黄色
public void getColor() {
System.out.println("黄色人种的皮肤颜色为黄色!");
}
@Override
//黄色人种讲话
public void talk() {
System.out.println("黄色人种会讲话,一般说的都是双字节!");
}
}
黑色人种:
package com.test.human;
/**
* 黑色人种
* 2015年9月18日 下午8:53:15
* @author 张耀晖
*
*/
public abstract class AbstractBlackHuman implements Human {
@Override
//黑色人种的皮肤颜色为黑色
public void getColor() {
System.out.println("黑色人种的皮肤颜色为黑色!");
}
@Override
//黑色人种讲话
public void talk() {
System.out.println("黑色人种会讲话,一般人听不懂!");
}
}
每个抽象类都有两个实现类,分别实现公共的最细节、最具体的事物:肤色和语言。具体的实现类肤色性别定义,以黄色女性人种为例。
其他的黑色人种、白色人种的男性和女性的代码与此类似,不再重复编写。
黄色女性人种:
package com.test.human;
/**
* 黄色女性人种
* 2015年9月18日 下午8:57:53
* @author 张耀晖
*
*/
public class WomenYellowHuman extends AbstractYellowHuman {
@Override
//黄人女性
public void getSex() {
System.out.println("黄人女性");
}
}
黄色男性人种:
package com.test.human;
/**
* 黄色男性人种
* 2015年9月18日 下午8:59:06
* @author 张耀晖
*
*/
public class MenYellowHuman extends AbstractYellowHuman {
@Override
//黄人男性
public void getSex() {
System.out.println("黄人男性");
}
}
八卦炉定义:
package com.test.factory;
import com.test.human.Human;
/**
* 八卦炉定义
* 2015年9月18日 下午9:03:35
* @author 张耀晖
*
*/
public interface HumanFactory {
//制造一个黄色人种
public Human createYellowHuman();
//制造一个黑色人种
public Human createBlackHuman();
//制造一个白色人种
public Human createWhiteHuman();
}
具体的八卦炉:
生产女性的八卦炉:
package com.test.factory;
import com.test.human.Human;
import com.test.human.WomenBlackHuman;
import com.test.human.WomenWhiteHuman;
import com.test.human.WomenYellowHuman;
/**
* 生产女性的八卦炉
* 2015年9月18日 下午9:05:53
* @author 张耀晖
*
*/
public class WomenFactory implements HumanFactory {
@Override
//生产出黄人女性
public Human createYellowHuman() {
return new WomenYellowHuman();
}
@Override
//生产出黑人女性
public Human createBlackHuman() {
return new WomenBlackHuman();
}
@Override
//生产出白人女性
public Human createWhiteHuman() {
return new WomenWhiteHuman();
}
}
生产男性的八卦炉:
package com.test.factory;
import com.test.human.Human;
import com.test.human.MenBlackHuman;
import com.test.human.MenWhiteHuman;
import com.test.human.MenYellowHuman;
/**
* 生产男性的八卦炉
* 2015年9月18日 下午9:11:20
* @author 张耀晖
*
*/
public class MenFactory implements HumanFactory {
@Override
//生产出黄人男性
public Human createYellowHuman() {
return new MenYellowHuman();
}
@Override
//生产出黑人男性
public Human createBlackHuman() {
return new MenBlackHuman();
}
@Override
//生产出白人男性
public Human createWhiteHuman() {
return new MenWhiteHuman();
}
}
女娲类(场景类):
package com.test.Client;
import com.test.factory.HumanFactory;
import com.test.factory.MenFactory;
import com.test.factory.WomenFactory;
import com.test.human.Human;
/**
* 女娲造人
* 2015年9月18日 下午9:18:56
* @author 张耀晖
*
*/
public class NvWa {
public static void main(String[] args) {
//第一条生产线,男性生产线
HumanFactory menFactory = new MenFactory();
//第二条生产线,女性生产线
HumanFactory womenFactory = new WomenFactory();
//生产线建立完毕,开始生产人
Human menYellowHuman = menFactory.createYellowHuman();
Human womenYellowHuman = womenFactory.createYellowHuman();
menYellowHuman.getColor();
menYellowHuman.talk();
menYellowHuman.getSex();
womenYellowHuman.getColor();
womenYellowHuman.talk();
womenYellowHuman.getSex();
//下面继续创建黑人和白人的男性和女性。。。。。。
}
}
运行结果:
抽象工厂模式的使用场景
抽象工厂模式的使用场景定义非常简单:一个对象族(或是一组没有任何关系的对象)都有相同的约束,则可以使用抽象工厂模式,什么意思呢?例如一个文本编辑器和一个图片处理器,都是软件实体,但是*nix下的文本编辑器和WINDOWS下的文本编辑器虽然功能和界面都相同,但是代码实现是不同的,图片处理器也是类似情况,也就是具有了共同的约束条件:操作系统类型,于是我们可以使用抽象工厂模式,产生不同操作系统下的编辑器和图片处理器。