工厂模式
用工厂方法代替new操作
什么情况下适合工厂模式
1.有一组相似的对象需要创建(比如说:创建毛巾的工厂不能用来创建汽车)
2.在编码时不能预计需要创建那种类的实例(比如说,创建水果,但是需要创建的水果有很多,暂时不知道需要创建多少水果)
项目中的现状:
在软件系统中经常面临着,对象的创建工作,由于需求的变化,这个对象可能随之也会发生变化,但它却拥有比较稳定的接口。
为此,我们需要提供一种封装机制来隔离出这个易变对象的变化,从而保证系统中其他依赖该对象的对象不随着需求变化而变化。
简单入门:
先定义一个接口
/**
* 发型接口
*/
public interface HairInterface {
//实现发型
public void draw();
}
在实现两个类:
/**
* 左偏分发型
*/
public class LeftHair implements HairInterface {
@Override
public void draw() {
System.out.println("左偏分发型");
}
}
package factory_mode;
public class RightHair implements HairInterface {
@Override
public void draw() {
System.out.println("这是右偏分发型");
}
}
在创建一个产品类;
package factory_mode;
/**
* 发型工厂
*/
public class HairFactory {
/**
* 根据类型来创建对象
*/
public HairInterface getHair(String key){
if("left".equals(key)){
return new LeftHair();
} else if ("right".equals(key)) {
return new RightHair();
}
return null;
}
}
调用:
package factory_mode;
public class FactoryTest {
public static void main(String[] args) {
/* HairInterface left = new LeftHair();
left.draw();*/
HairFactory hairFactory = new HairFactory();
HairInterface left = hairFactory.getHair("left");
if(left != null) {
left.draw();
}
}
}
这个时候,工厂模式的优点就出现了,首先,客户端不需要创建对象了,直接给一个left就可以创建出一个对象,也不需要记忆很多类名。产品的实现和客户端进行了分离。
但是,现在有一个缺点,当我需要增加其他的类的时候,需要在else if 里面进行加
增加一个加一行,很麻烦。而且这里要进行判断,效率也慢,于是我们就通过类名,通过反射来创建对象。
/**
* 利用类名来生产对象
*/
public HairInterface getHairByClass(String className){
try {
HairInterface hair = (HairInterface)Class.forName(className).newInstance();
return hair;
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
}
return null;
}
代码如下:
测试如下:
package factory_mode;
public class FactoryTest {
public static void main(String[] args) {
/* HairInterface left = new LeftHair();
left.draw();*/
HairFactory hairFactory = new HairFactory();
/* HairInterface left = hairFactory.getHair("left");
if(left != null) {
left.draw();
}*/
hairFactory.getHairByClass("factory_mode.LeftHair").draw();
}
}
可以达到预期效果。这样在增加一个发型,我们不需要用else if 了。自己通过类名创建。
但是,这个类名是全类名,感觉还是挺麻烦的,这里我在对其进行升级。
/**
* 利用类名来生产对象
*/
public <T extends HairInterface> HairInterface getHairByClass(Class<T> c){
try {
HairInterface hair = (HairInterface)Class.forName(c.getName()).newInstance();
return hair;
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
}
return null;
}
升级如下:现在只需要传入class文件即可。而且引进了泛型,传入的类必须是集成HairInterface接口。对输入的类进行了一个限制。
此时,客户端的代码就如下:
package factory_mode;
public class FactoryTest {
public static void main(String[] args) {
/* HairInterface left = new LeftHair();
left.draw();*/
HairFactory hairFactory = new HairFactory();
/* HairInterface left = hairFactory.getHair("left");
if(left != null) {
left.draw();
}*/
hairFactory.getHairByClass(RightHair.class).draw();
}
}
这时候,我新建了一个类的时;
package factory_mode;
public class InHair implements HairInterface {
@Override
public void draw() {
System.out.println("这是中分发型");
}
}
客户端也可以直接进行测试,无须通过修改工厂类以及其他
如上:已经可以实现了一个发型工厂实现类,这个类可以产生各种发型。
但是 要是有系列的话就不一样了。比如说圣诞系列的头发,而且每个系列都是有男孩女孩,当然,以上代码也可以实现,但是效果就非常不好,而且会显得很臃肿。
这时候,就需要抽象工厂模式了。
抽象工厂模式定义
为创建一组相关或者相互依赖的对象提供一个接口,无需指定它们的具体类。
由于我们的需求是,需要有男孩女孩,有需要不同有不同的系列,所以,用普通工厂模式就不行了。
首先我需要创建男孩和女孩就需要一个工厂,这个工厂设置为接口,不是像刚才一样的类
package factory_mode;
/**
* 人物的实现接口
*/
public interface PersonFactory {
//男孩接口
public Boy getBoy();
// 女孩接口
public Girl getGirl();
}
然后男孩和女孩也是接口
package factory_mode;
/**
* 男孩
*
*/
public interface Boy {
public void drawMan();
}
package factory_mode;
/**
* 女孩
*/
public interface Girl {
public void drawWomen();
}
每个男孩有很多系列,假设有新年系列和圣诞系列
package factory_mode;
/**
* 新年系列的男孩子
*/
public class HNBoy implements Boy {
@Override
public void drawMan() {
System.out.println("新年系列的男孩子");
}
}
package factory_mode;
public class MCBoy implements Boy {
@Override
public void drawMan() {
System.out.println("圣诞系列的男孩子");
}
}
女孩也是有新年系列和圣诞系列
package factory_mode;
/**
* 圣诞系列的女孩
*/
public class MCGirl implements Girl {
@Override
public void drawWomen() {
System.out.println("圣诞系列的女孩");
}
}
package factory_mode;
public class HNGirl implements Girl {
@Override
public void drawWomen() {
System.out.println("圣诞系列的女孩");
}
}
这时候,就可以用圣诞系列的工厂来创建圣诞系列的男孩或者女孩了
package factory_mode;
/**
* 圣诞系列加工厂
*/
public class MCFctory implements PersonFactory {
@Override
public Boy getBoy() {
return new MCBoy();
}
@Override
public Girl getGirl() {
return new MCGirl();
}
}
这样当客户端需要圣诞男孩时,只需要调用MCFtory的getBoy()方法就好了。
上面这个案例的因素数有两个 第一个性别 第二个因素为系列 ,不管有多少性别和多少系列。都只有两个因素而已。对于有两个因素的,就应该使用抽象工厂模式。把工厂用接口实现。
下面在来举一个例子:
假设我要生产产品,假设产品有等级、和种类两个因素。假设我需要生成两个等级,三个种类的产品。
首先我先写一个产品抽象类;
package factory_mode.product;
/**
* 抽象产品类
*/
public abstract class AbstractProduct {
public void shareMethod(){
System.out.println("这是产品类的公共方法");
}
//每个产品相同方法,不同实现
public abstract void doSomething();
}
然后,再写上三个具体的产品实现类ABC;
package factory_mode.product;
public class ProductA extends AbstractProduct {
@Override
public void doSomething() {
System.out.println("我是产品A");
}
}
public class ProductB extends AbstractProduct {
@Override
public void doSomething() {
System.out.println("我是产品B");
}
}
public class ProductC extends AbstractProduct {
@Override
public void doSomething() {
System.out.println("我是产品C");
}
}
在创建三款普通级产品
public class SubProductA extends AbstractProduct {
@Override
public void doSomething() {
System.out.println("我是普通款产品A");
}
}
public class SubProductB extends AbstractProduct {
@Override
public void doSomething() {
System.out.println("我是普通款产品B");
}
}
public class SubProductC extends AbstractProduct {
@Override
public void doSomething() {
System.out.println("我是普通款产品C");
}
}
这样六款产品就好了,其中有两个因素,产品的等级和产品的种类;
重点来了:下面需要创建一个抽象工厂,有几个产品等级就需要有几个创建方法
这里其实是解决了一个因素 就是解决产品种类的这个因素;
package factory_mode.product;
/**
* 抽象工厂
* 有几个产品等级,就需要有几个创建方法
*/
public interface AbstracCreator {
//创建A产品
public AbstractProduct createProductA();
//创建B产品
public AbstractProduct createProductB();
//创建C产品
public AbstractProduct createProductC();
}
然后,在创建三个具体的实现类
这里其实是解决了产品等级的这个因素:
package factory_mode.product;
/**
* 实现了抽象工厂
* 只创建高级别的产品
*/
public class Creator implements AbstracCreator {
@Override
public AbstractProduct createProductA() {
System.out.println("创建高级款的产品A");
return new ProductA();
}
@Override
public AbstractProduct createProductB() {
System.out.println("创建高级款的产品B");
return new ProductB();
}
@Override
public AbstractProduct createProductC() {
System.out.println("创建高级款的产品C");
return new ProductC();
}
}
package factory_mode.product;
public class SubCreator implements AbstracCreator {
@Override
public AbstractProduct createProductA() {
System.out.println("创建普通款的产品A");
return new SubProductA();
}
@Override
public AbstractProduct createProductB() {
System.out.println("创建普通款的产品B");
return new SubProductB();
}
@Override
public AbstractProduct createProductC() {
System.out.println("创建普通款的产品C");
return new SubProductC();
}
}
抽象工厂写了两次,第一次是接口,解决的是三个产品的问题,第二次是实现,解决的是等级的问题,一个实现类,只解决一个等级的问题,比如说高级。这样就解决了两个因素的抽象工厂的问题了。
经过测试,发现完全可以符合要求,
客户端不知道对象是如何创建出来的,达到了松耦合的作用。