设计模式之工厂模式
什么是工厂模式:
是用工厂方法代替new操作的一种模式。著名的Jive论坛 ,就大量使用了工厂模式,工厂模式在Java程序系统可以说是随处可见。因为工厂模式就相当于创建实例对象的new,我们经常要根据类Class生成实例对象,如A a=new A() 工厂模式也是用来创建实例对象的,所以以后new时就要多个心眼,是否可以考虑使用工厂模式,虽然这样做,可能多做一些工作,但会给你系统带来更大的可扩展性和尽量少的修改量。
工厂模式分类
1)简单工厂模式(Simple Factory):不利于产生系列产品;
2)工厂方法模式(Factory Method):又称为多形性工厂;
3)抽象工厂模式(Abstract Factory):又称为工具箱,产生产品族,但不利于产生新的产品;
这三种模式从上到下逐步抽象,并且更具一般性。GOF在《设计模式》一书中将工厂模式分为两类:工厂方法模式(Factory Method)与抽象工厂模式(Abstract Factory)。将简单工厂模式(Simple Factory)看为工厂方法模式的一种特例,两者归为一类。
工厂模式的意图:
定义一个接口来创建对象,但是让子类来决定哪些类需要实例化。工厂方法把实例化的工作推到子类当中去实现。
什么情况适合工程模式:
- 有一组类似的对象需要创建。
- 在编码时不能预见哪种类需要创建实例。
- 系统需要扩展性,不应该产品类实例如何被创建、组合和表达的细节。
项目中的现状:
在软件系统中经常面临着“对象”的创建工作,由于需求的变化,我这个问题可能随时也会发生,但他却拥有比较稳定的接口,为此,我们需要提供一种分装机制来隔离这个易变对象的变化,从而保持系统中其他该对象的对象不再随着变化而变化。
代码设计:
1. 尽量松耦合,一个对象的依赖对象变化与本身无关。
2. 具体产品与客户剥离,责任分割。
怎么使用工厂模式
简单工厂模式:
IProduct
/**
* 产品接口
*/
public interface IProduct {
public void IProduct();
}
Product1
/**
* Product1
*/
public class Product1 implements IProduct{
@Override
public void IProduct() {
System.out.println("product1");
}
}
Product2
/**
* Product2
*/
public class Product2 implements IProduct{
@Override
public void IProduct() {
System.out.println("Product2");
}
}
ProductFactory
/**
* 工厂类
*/
public class ProductFactory {
public IProduct getProduct(String key){
if("product1".equals(key)){
return new Product1();
}else if("product2".equals(key)){
return new Product2();
}
return null;
}
}
Test
public class Test {
public static void main(String[] args) {
ProductFactory factory = new ProductFactory();
IProduct product = factory.getProduct("product1");
product.IProduct();
}
}
//结果是product1
对Factory类的改进:
如果我们新添加product3则要在工厂类中添加一个条件判断。我们可以通过反射机制,通过类的名称来创建类的实例。
public class ProductFactory {
/**
* 根据类的名称获取对象
* @param classname
* @return
*/
public IProduct getProduct(String classname){
try {
IProduct product = (IProduct) Class.forName(classname).newInstance();
return product;
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
}
public class Test {
public static void main(String[] args) {
ProductFactory factory = new ProductFactory();
//在getProduct中要传入全路径的类名
IProduct product = factory.getProduct("gongchang.Product1");
product.IProduct();
}
}
//结果为 product1
还可以添加映射文件,添加读取映射文件的类或者方法。使获取对象时更简单
工厂方法模式
- 添加工厂接口,让每个建立没个产品的工厂。
IProduct
/**
* 产品接口
*/
public interface IProduct {
public void IProduct();
}
Product1
/**
* Product1
*/
public class Product1 implements IProduct{
@Override
public void IProduct() {
System.out.println("product1");
}
}
Product2
/**
* Product2
*/
public class Product2 implements IProduct{
@Override
public void IProduct() {
System.out.println("Product2");
}
}
ProductFactory
/**
* 工厂类
*/
public interface ProductFactory {
public IProduct getProduct();
}
Product2Factory
public class Product2Factory implements ProductFactory{
@Override
public IProduct getProduct();
{
return new Product2();
}
}
Test
public class Test {
public static void main(String[] args) {
Product2Factory factory = new Product2Factory ();
IProduct product = factory.getProduct();
product.IProduct();
}
}
//结果是product2
抽象工厂模式:
随着客户的要求越来越高,产品需要配置包装。于是这个工厂开始生产产品和配置需要的包装。这时候工厂有二个系列的产品:产品和包装.产品必须使用对应的包装.这时候分别使用一个产品工厂和一个包装工厂都不能满足我们的需求,我们必须确认产品和包装的对应关系。因此把产品工厂跟包装工厂联系在一起。因此出现了抽象工厂模式。
可以说,抽象工厂模式和工厂方法模式的区别就在于需要创建对象的复杂程度上。而且抽象工厂模式是三个里面最为抽象、最具一般性的。
抽象工厂模式的用意为:给客户端提供一个接口,可以创建多个产品族中的产品对象 ,而且使用抽象工厂模式还要满足一下条件:
1. 系统中有多个产品族,而系统一次只可能消费其中一族产品。
2. 同属于同一个产品族的产品以其使用。
抽象工厂模式的各个角色(和工厂方法一样):
1. 抽象工厂角色: 这是工厂方法模式的核心,它与应用程序无关。是具体工厂角色必须实现的接口或者必须继承的父类。在java中它由抽象类或者接口来实现。
2. 具体工厂角色:它含有和具体业务逻辑有关的代码。由应用程序调用以创建对应的具体产品的对象。
3. 抽象产品角色:它是具体产品继承的父类或者是实现的接口。
4. 具体产品角色:具体工厂角色所创建的对象就是此角色的实例。
code:
/**
* 包装类的接口
*
*/
public interface Ipack {
public void Ipack();
}
//包装1
public class Pack1 implements Ipack{
@Override
public void Ipack() {
System.out.println("pack1");
}
}
//包装2
public class Pack2 implements Ipack{
@Override
public void Ipack() {
System.out.println("pack2");
}
}
/**
* 抽象工厂类
*/
public abstract class AbstaractFactory {
public abstract Ipack getPack();
public abstract IProduct getProduct();
}
//产品包装为2的工厂类(还有其他工厂类)
public class Product2Factory extends AbstaractFactory{
@Override
public Ipack getPack() {
return new Pack2();
}
@Override
public IProduct getProduct() {
return new Product2();
}
}