工厂模式的简单介绍:为了降低程序的耦合性,增加程序的可扩展性和易维护性,提供的一种创建对象的方法。客户不需要直接new一个对象出来,可以直接去找相应的工厂来生产对象即可。这样,客户可以不去也不需要去了解创建对象的细节。而且,如果你是广泛采用new对象的方法,那你以后想修改对象的话,就需要找到所有的new。如果使用工厂的话,工厂的类型直接由配置文件来决定。需要修改类型时,你可以直接去修改配置文件,源代码甚至可以不用去修改。
工厂模式分为:
1.简单工厂(Simple Factory): 一个具体工厂,一个抽象产品,多个具体产品
2.工厂方法(Factory Method): 一个抽象工厂,多个具体工厂,一个抽象产品,多个具体产品
3.抽象工厂(Abstract Factory):一个抽象工厂,多个具体工厂,多个抽象产品,多个具体产品
4.介绍Spring中的BeanFactory使用和手动仿制一个Spring的bean工厂
简单工厂
目的:降低耦合,客户不需要知道产品的具体生产方式。
缺点:只有一个工厂,这个工厂任务繁重。
汽车类
public class Car implements Vehicle{
public void run(){
System.out.println("突突突突....I'm car");
}
}
飞机类
public class Plane implements Vehicle{
public void run() {
System.out.println("嗖嗖嗖嗖....I'm plane");
}
}
工厂类
public class Factory {
public Car getCar(){
return new Car();
}
public Plane getPlane(){
return new Plane();
}
}
调用方法
public static void main(String[] args) {
Factory f =new Factory();
//拿到一辆车
Vehicle vehicle=f.getCar();
vehicle.run();
//拿到一架飞机
vehicle =f.getPlane();
vehicle.run();
}
工厂方法
目的:在简单工厂的基础上,减少工厂的负担,将工厂个类型细化,抽象出一个总的工厂。
缺点:只能生产固定类型的产品,即只能生产交通工具。如果每辆交通工具上还要配备武器、吃的,那我们只能创建武器、吃的的工厂。这样,工厂发生了泛滥,而且结构混乱。
优点:达成了目的,可以在产品层上任意扩展(想提供创建轮船的服务,只需要添加Ship和ShipFactory类即可)。
Car、Plane、Vechile和简单工厂一样,不列出代码
VehicleFactory接口
public interface VehicleFactory {
public Vehicle getVechicle();
}
汽车工厂
public class CarFactory implements VehicleFactory{
public Vehicle getVechicle() {
return new Car();
}
}
飞机工厂
public class PlaneFactory implements VehicleFactory{
public Vehicle getVechicle() {
return new Plane();
}
}
调用方法
public static void main(String[] args) {
VehicleFactory factory =new CarFactory();
factory.getVechicle().run();//生产出来的汽车run
VehicleFactory f =new PlaneFactory();
f.getVechicle().run();//生产出来的飞机run
}
抽象工厂
目的:解决工厂方法不能创建一系列产品的短板。
缺点:产品的扩展性差,只能生产固定系列的产品。
优点:实现了产品的系列化生产。
AK47
public class AK47 implements Weapon{
public void shoot() {
System.out.println("哒哒哒嗒...I'm AK47");
}
}
NutterTools
public class NutterTools implements Weapon{
public void shoot() {
System.out.println("批次咔哧...I'm NutterTools");
}
}
GFSFactory
//高富帅的工厂
public class GFSFactory implements WeaponFactory,VehicleFactory{
//高富帅坐飞机
public Vehicle getVechicle() {
return new Plane();
}
//高富帅保镖需要AK
public Weapon getWeapon() {
return new AK47();
}
}
NutterFactory
//暴徒的工厂
public class NutterFactory implements VehicleFactory,WeaponFactory{
//生产汽车
public Vehicle getVechicle() {
return new Car();
}
//生产暴徒武器
public Weapon getWeapon() {
return new NutterTools();
}
}
================================================
什么是JavaBean?大致上可以这么理解:一种封装属性和方法来实现特殊功能的特殊对象。(加了复杂定语的对象)
JavaBean的结构很简单:
1.属性(私有):xxx
2.方法(公开):getXxx()、setXxx()
这种对象可以使用“内省”来操作它!
Spring提供了这种特殊对象的生产工厂的方法。这种工厂就是我们要介绍的BeanFactory。
看虾面的代码:
//还是我们上面定义的Vehicle接口
public interface Vehicle {
void run();
}
//汽车类
public class Car implements Vehicle{
public void run(){
System.out.println("突突突突....I'm car");
}
}
我们想使用Spring中的Bean工厂来生产汽车,就先把Spring的jar包全部导入进来(Spring的jar和logging的jar)。
Spring的BeanFactory使用前,为他配一个xml的配置文件。
applicationContext.xml内容如下:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<!-- id相当于key、名字 class就是你类所在的完整目录 -->
<!-- v=com.majin.BeanFactory.Car -->
<bean id="v" class="com.majin.BeanFactory.Car">
</bean>
</beans>
如下调用就可以的到你想要的对象了。
public static void main(String[] args) {
BeanFactory factory =new ClassPathXmlApplicationContext("applicationContext.xml");
Object o =factory.getBean("v");
Vehicle v =(Vehicle)o;
v.run();
}
这么做的好处大大的,你想啊,客户想修改一下程序,怎么修改?找配置文件啊。客户想扩展一下程序,怎么扩展?在你的应用文档中告诉客户实现那个接口,改一下配置文件啊。
================================================
觉得BeanFactory有点意思了吧。我们其实完全可以“自己动手,丰衣足食”,自己造一个和Spring的Bean工厂一样的工厂出来。(实际上,没必要自己去造)。
我们就需要自己去解析xml文件了,我采用的是dom4j来解析的(方法不唯一),导入dom4j的所有jar包。
代码如下:
//在Spring中BeanFactory就是一个接口,我们做一个相同的接口
public interface BeanFactory {
public Object getBean(String id);
}
//定义实现BeanFactory的类(照猫画虎)
public class ClassPathXmlApplicationContext implements BeanFactory {
// the container of object
Map<String, Object> container = new HashMap<String, Object>();
/**
* constructor of ClassPathXmlApplicationContext
* @param path
* the position of the xml
* @throws Exception
* class not found
*/
public ClassPathXmlApplicationContext(String fileName)
throws InstantiationException, IllegalAccessException, Exception {
//根据fileName解析xml,把里面所有的<bean>中的id、class解析出来,存到我们的容器中。
SAXReader reader = new SAXReader();
Document document = reader.read(filename);
Element root = document.getRootElement();
Iterator it =root.elementIterator("bean");
while (it.hasNext()) {
Element e = (Element) it.next();
String id = e.attributeValue("id");
String clazz = e.attributeValue("class");
// create the instance of the clazz
Object o = Class.forName(clazz).newInstance();
container.put(id, o);
}
}
@Override
public Object getBean(String id) {
return container.get(id);
}
}
//同样的调用,同样的结果
public static void main(String[] args) throws Exception {
BeanFactory factory =new ClassPathXmlApplicationContext("xml/applicationContext.xml");
Object o = factory.getBean("v");
Vehicle v = (Vehicle)o;
v.run();
}