设计模式之简单工厂模式和工厂方法模式

1 简单工厂模式的定义

1.1 简单工厂模式的通用类图

在这里插入图片描述

1.2 简单工厂模式的实用通用源码

(1) 抽象产品类

public abstract class Product {
	public void method1(){
		// 业务逻辑处理
	}
	
	// 抽象方法
	public abstract void method2();
}

(2) 具体产品类1、2

/**
 * 具体的产品类可以有多个,都继承于抽象产品类
 */
public class ConcreteProduct1 extends Product {
	public void method2() {
		//业务逻辑处理
	}
}

public class ConcreteProduct2 extends Product {
	public void method2() {
		//业务逻辑处理
	}
}

(3)具体工厂类

public class Creator {
    /**
     * 简单工厂模式或者静态工厂模式
     * @param clz 产品对象类类型
     * @return 具体的产品对象
     */
    public static <T extends Product> T createProduct(Class<T> clz) {
        Product product = null;
        try {
            product = (Product) Class.forName(clz.getName()).newInstance();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return (T)product;
    }
}

(4) 场景类

public class Client {
	public static void main(String[] args) {
		Product product1 = Creator.createProduct(ConcreteProduct1.class);
		Product product2 = Creator.createProduct(ConcreteProduct2.class);
	}
}

1.3 总结

一个抽象产品类,可以派生出多个具体产品类。一个具体工厂类,通过往此工厂的static方法中传入不同参数,产出不同的具体产品类实例。

2 工厂方法模式的定义

2.1 工厂方法模式的通用类图

在这里插入图片描述

2.2 工厂方法模式的实用通用源码

(1) 抽象产品类

public abstract class Product { 
	public void method1(){
		//业务逻辑处理
	}
	
	//抽象方法
	public abstract void method2();
}

(2) 具体产品类1、2

/**
 * 具体的产品类可以有多个,都继承于抽象产品类
 */
public class ConcreteProduct1 extends Product {
	public void method2() {
		//业务逻辑处理
	}
}

public class ConcreteProduct2 extends Product {
	public void method2() {
		//业务逻辑处理
	}
}

(3) 抽象工厂类

/**
 * 抽象工厂类负责定义产品对象的产生
 */
public abstract class Creator { 
	// 创建一个产品对象,其输入参数类型可以自行设置通常为String、Enum、Class等,当然也可以为空
	public abstract <T extends Product> T createProduct(Class<T> c);
}

(4)具体工厂类A

/**
 * 具体如何产生一个产品的对象,是由具体的工厂类实现的
 */
public class ConcreteCreatorA extends Creator {
	public <T extends Product> T createProduct(Class<T> c) { 
		Product product=null;
		try {
			product =(Product)Class.forName(c.getName()).newInstance();
		} catch (Exception e) {
		
		}
		return (T)product;
	}
}

(5)具体工厂类B

/**
 * 具体如何产生一个产品的对象,是由具体的工厂类实现的
 */
public class ConcreteCreatorB extends Creator {
	public <T extends Product> T createProduct(Class<T> c) { 
		Product product=null;
		try {
			product =(Product)Class.forName(c.getName()).newInstance();
		} catch (Exception e) {
		
		}
		return (T)product;
	}
}

(5) 场景类

public class Client {
	public static void main(String[] args) {
		Creator creatorA = new ConcreteCreatorA();
		Product productA1 =creatorA.createProduct(ConcreteProduct1.class);
		Product productA2 =creatorA.createProduct(ConcreteProduct2.class);
        
        Creator creatorB = new ConcreteCreatorB();
		Product productB1 =creatorB.createProduct(ConcreteProduct1.class);
		Product productB2 =creatorB.createProduct(ConcreteProduct2.class);
	}
}

2.3 总结

一个抽象产品类,可以派生出多个具体产品类。一个抽象工厂类,可以派生出多个具体工厂类。每个具体工厂类只能创建一个具体产品类的实例。

3 工厂方法模式实战

(1) 抽象产品类,IoHandler.java

public abstract class IoHandler {
    public abstract void add(String id,String name);
    public abstract void remove(String id,String name);
    public abstract void update(String id,String name);
    public abstract String query(String id);
}

(2) 具体产品类,DBHandler.java,FileHandler.java,XmlHandler.java

public class DBHandler extends IoHandler{
    @Override
    public void add(String id, String name) {
    }

    @Override
    public void remove(String id, String name) {
    }

    @Override
    public void update(String id, String name) {
    }

    @Override
    public String query(String id) {
        return "DBHandler";
    }
}
public class FileHandler extends IoHandler {
    @Override
    public void add(String id, String name) {
    }

    @Override
    public void remove(String id, String name) {
    }

    @Override
    public void update(String id, String name) {
    }

    @Override
    public String query(String id) {
        return "FileHandler";
    }
}
public class XmlHandler extends IoHandler {
    @Override
    public void add(String id, String name) {
    }

    @Override
    public void remove(String id, String name) {
    }

    @Override
    public void update(String id, String name) {
    }

    @Override
    public String query(String id) {
        return "SMBrother";
    }
}

(3) 抽象工厂类,Factory.java

public abstract class Factory {
    public abstract <T extends IoHandler> T getIOHandler(Class<T> clz);
}

(4)具体工厂类,IOFactory.java

public class IOFactory extends Factory {

    public <T extends IoHandler> T getIOHandler(Class<T> clz) {
        IoHandler handler = null;
        try {
            handler = (IoHandler)Class.forName(clz.getName()).newInstance();
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
        return (T) handler;
    }
}

(6) 场景类

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        final TextView tvContent = (TextView) findViewById(R.id.tvContent);

        IOFactory factory = new IOFactory();
       
        // 获取查询普通文件数据
        Button btnFile = (Button) findViewById(R.id.btnFile);
        btnFile.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                IoHandler handler = factory.getIOHandler(FileHandler.class);
                tvContent.setText(handler.query("333333333"));
            }
        });

        // 获取查询Xml文件数据
        Button btnXml = (Button) findViewById(R.id.btnXml);
        btnXml.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                IoHandler handler = factory.getIOHandler(XmlHandler.class);
                tvContent.setText(handler.query("333333333"));
            }
        });

        // 获取查询数据库文件数据
        Button btnDB = (Button) findViewById(R.id.btnDB);
        btnDB.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                IoHandler handler = factory.getIOHandler(DBHandler.class);
                tvContent.setText(handler.query("333333333"));
            }
        });
    }
}

(6) 结果演示
这里写图片描述

4 工厂方法模式的应用

4.1 工厂方法模式的优点

(1)良好的封装性,代码结构清晰。一个对象创建是有条件约束的,如一个调用者需要一个具体的产品对象,只要知道这个产品的类名(或约束字符串)就可以了,不用知道创建对象的过程,降低模块间的耦合。

(2)工厂方法模式的扩展性非常优秀。在增加产品类的情况下,只要适当地修改具体的工厂类或扩展一个工厂类,就可以完成“拥抱变化”。例如在我们的例子中,需要增加一个棕色人种,则只需要增加一个ConcreteProduct3类,工厂类不用任何修改就可完成系统扩展。

(3)屏蔽产品类。这一特点非常重要,调用者不需要关心产品类的实现是如何变化的,它只需要关心产品的接口,只要接口保持不变系统中的上层模块就不要发生变化。因为产品类的实例化工作是由工厂类负责的,一个产品对象具体由哪一个产品生成是由工厂类决定的。

(4)工厂方法模式是典型的解耦框架。高层模块值需要知道产品的抽象类,其他的实现类都不用关心,符合迪米特法则,我不需要的就不要去交流;也符合依赖倒置原则,只依赖产品类的抽象;当然也符合里氏替换原则,使用产品子类替换产品父类!

4.2 工厂方法模式的使用场景

(1)工厂方法模式是new一个对象的替代品。所以在所有需要生成对象的地方都可以使用,但是需要慎重地考虑是否要增加一个工厂类进行管理,增加代码的复杂度。

(2)需要灵活的、可扩展的框架时,可以考虑采用工厂方法模式。例如需要设计一个连接邮件服务器的框架,有三种网络协议可供选择:POP3、IMAP、HTTP,我们就可以把这三种连接方法作为产品类,定义一个接口如:IConnectMail,然后定义对邮件的操作方法,用不同的方法实现三个具体的产品类再定义一个工厂方法,按照不同的传入条件,选择不同的连接方式。如此设计可以做到完美的扩展,如某些邮件服务器提供了WebService接口,我们只要增加一个产品类就可以了。

(3)工厂方法模式可以用在异构项目中。例如通过WebService与一个非Java的项目交互,虽然WebService号称是可以做到异构系统的同构化,但是在实际的开发中,还是会碰到很多问题,如类型问题、WSDL文件的支持问题,等等。从WSDL中产生的对象都认为是一个产品,然后由一个具体的工厂类进行管理,减少与外围系统的耦合。

(4)使用在测试驱动开发的框架下。例如测试一个类A,就需要把与类A有关联关系的类B也同时产生出来,我们可以使用工厂方法模式把类B虚拟出来,避免类A与类B的耦合。目前由于JMock和EasyMock的诞生,该使用场景已经弱化了,读者可以在遇到此种情况时直接考虑使用JMock或EasyMock。

5 扩展

5.1 替代单例模式

单例模式的核心要求就是在内存中只有一个对象,通过工厂方法模式也可以只在内存中生产一个对象。
这里写图片描述
非常简单的类图,Singleton定义了一个private的无参构造函数,目的是不允许通过new的方式创建一个对象。
(1) 单例类

public class Singleton { 
	// 不允许通过new产生一个对象
	private Singleton(){
	}
	public void doSomething(){
		// 业务处理
	}
}

(2)负责生成单例的工厂类

/**
 * Singleton保证不能通过正常的渠道建立一个对象,那SingletonFactory通过反射方式创建建立一个单例对象
 */
public class SingletonFactory {
	private static Singleton singleton; 
	static{
		try {
			Class cl= Class.forName(Singleton.class.getName()); // 获得无参构造
			Constructor constructor=cl.getDeclaredConstructor(); // 设置无参构造是可访问的
			constructor.setAccessible(true); // 产生一个实例对象
			singleton = (Singleton)constructor.newInstance();
		} catch (Exception e) {
			// 异常处理
		}
    }
    
	public static Singleton getSingleton(){ 
		return singleton;
	}
}

通过获得类构造器,然后设置访问权限生成一个对象,然后提供外部访问,保证内存中的对象唯一。以上通过工厂方法模式创建了一个单例对象,该框架可以继续扩展,在一个项目中可以产生一个单例构造器,所有需要产生单例的类都遵循一定的规则(构造方法是private),然后通过扩展该框架,只要输入一个类型就可以获得唯一的一个实例。

5.2 延迟初始化

一个对象被消费完毕后,并不立刻释放,工厂类保持其初始状态,等待再次被使用。
这里写图片描述
ProductFactory负责产品类对象的创建工作,并且通过prMap变量产生一个缓存,对需要再次被重用的对象保留,Product和ConcreteProduct是一个示例代码,请参考前面的代码。

(1) 延迟加载的工厂类

public class ProductFactory {
	private static final Map<String,Product> prMap = new HashMap();
	public static synchronized	Product createProduct(String type) throws Excep;
	// 如果Map中已经有这个对象
	Product product =null;
	
	if(prMap.containsKey(type)){ 
		product = prMap.get(type);
	} else {
		if(type.equals("Product1")) {
			product = new ConcreteProduct1();
		} else {
			product = new ConcreteProduct2();
		}
		// 同时把对象放到缓存容器中
		prMap.put(type,product);
	}
	return product;
}

代码还比较简单,通过定义一个Map容器,容纳所有产生的对象,如果在Map容器中已经有的对象,则直接取出返回;如果没有,则根据需要的类型产生一个对象并放入到Map容器中,以方便下次调用。
延迟加载框架是可以扩展的,例如限制某一个产品类的最大实例化数量,可以通过判断Map中已有的对象数量来实现。例如JDBC连接数据库,都会要求设置一个MaxConnections最大连接数量,该数量就是内存中最大实例化的数量。

6 参考文章

《Android源码设计模式解析与实战》

《设计模式之禅》

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值