java设计模式-工厂系列
一、简单工厂
1.背景:
任意定制交通工具的类型和生产过程
代码:
Moveable.java
package com.cy.dp.factory; public interface Moveable { void run(); }
Car.java:
package com.cy.dp.factory; public class Car implements Moveable{ @Override public void run(){ System.out.println("car running..."); } }
Plane:
package com.cy.dp.factory; public class Plane implements Moveable{ @Override public void run() { System.out.println("plane running..."); } }
VehicleFactory.java:
package com.cy.dp.factory; /** * 交通工具工厂 * @author CY * */ public abstract class VehicleFactory { abstract Moveable create(); }
CarFactory:
package com.cy.dp.factory; public class CarFactory extends VehicleFactory{ @Override Moveable create() { return new Car(); } }
PlaneFactory:
package com.cy.dp.factory; public class PlaneFactory extends VehicleFactory{ @Override Moveable create() { return new Plane(); } }
Test测试类:
package com.cy.dp.factory; public class Test { public static void main(String[] args) { VehicleFactory factory = new CarFactory(); Moveable m = factory.create(); m.run(); } }
question:
要不要把工厂VehicleFactory设计成接口?
答:可以,接口和抽象类其实是一回事;什么时候用抽象类,什么时候用接口?基本上可以采用这样的方式:如果说这个概念在我们脑中确确实实存在的,那你就用抽象类;如果说这个概念仅仅是某些方面的一个特性,比如说会飞的,能跑的,像这一类的东西,我们就把它设计成接口;如果是比较模糊的概念,不知道设计成抽象类还是接口时,那么设计成接口,原因是我们实现了这个接口之后,还可以从其他的抽象类来继承,更灵活。
二、抽象工厂
控制一系列产品(车、武器、食品...)的替换,举个例子,家里搞装修,现在海尔卖那种整体厨房,油烟机、地板、热水器、微波炉...等等,你能不能够做到我要把一系列产品替换掉的话,它就全替换掉了。这件事情该怎么做呢?
代码:
Vechile:
package com.cy.dp.factory; //交通工具 public abstract class Vehicle { abstract void run(); }
Weapon:
package com.cy.dp.factory; //武器 public abstract class Weapon { abstract void shoot(); }
Food:
package com.cy.dp.factory; //食物 public abstract class Food { abstract void printName(); }
Car:
package com.cy.dp.factory; public class Car extends Vehicle{ public void run(){ System.out.println("car running..."); } }
AK47:
package com.cy.dp.factory; public class AK47 extends Weapon{ public void shoot(){ System.out.println("shooting..."); } }
Apple:
package com.cy.dp.factory; public class Apple extends Food{ public void printName(){ System.out.println("apple"); } }
AbstractFactory:
package com.cy.dp.factory; public abstract class AbstractFactory { abstract Vehicle createVehicle(); abstract Weapon createWeapon(); abstract Food createFood(); }
DefaultFactory:(默认工厂,生产汽车、AK47、苹果)
package com.cy.dp.factory; public class DefaultFactory extends AbstractFactory{ @Override Vehicle createVehicle() { return new Car(); } @Override Weapon createWeapon() { return new AK47(); } @Override Food createFood() { return new Apple(); } }
Test:
package com.cy.dp.factory; public class Test { public static void main(String[] args) { AbstractFactory f = new DefaultFactory(); Vehicle v = f.createVehicle(); v.run(); Weapon w = f.createWeapon(); w.shoot(); Food a = f.createFood(); a.printName(); } }
抽奖工厂好处:
好处:如果自己对这一系列东西不满意了,添加自己的系列产品,交通工具从Vehicle继承,武器从Weapon继承... 然后再产生自己的工厂,不用再修改自己的代码,只需要改AbstractFactory f = new DefaultFactory()这一个地方;如果写在配置文件里,甚至源代码再也不用变了;只改配置文件就ok;
抽象工厂:是它生产了一系列产品,如果你想换掉一系列产品的时候,或者在这一系列产品基础之上进行扩展,想产生新的系列产品以及想对这一系列产品的生产过程进行控制,用抽象工厂。
比较上面两种简单工厂和抽象工厂:
问:抽象工厂和普通的工厂比较,有哪些好的和不好的?
对于普通的工厂来说,可以在产品这个维度进行扩展,可以扩展产品,扩展生产产品的工厂;如果在普通工厂里面产生产品系列,就会很麻烦,比如扩展apple,就要多一个appleFactory,最后就发现工厂泛滥;所以普通的工厂方法来说最后会产生工厂泛滥这种问题;
但是对于抽象工厂来说,也有短处,不能扩展新的产品品种,比如上面有Food、Vehicle、Weapon,想要加一个盔甲,那么AbstractFactory就要加一个create盔甲的抽象方法,所有继承AbstractFactory的类也要加实现,就太麻烦了;
三、spring的bean工厂
模拟spring的bean工厂:
代码:
BeanFactory:
package com.bjsxt.spring.factory; public interface BeanFactory { Object getBean(String id); }
ClassPathXmlApplicationContext:
package com.bjsxt.spring.factory; import java.util.HashMap; import java.util.List; import java.util.Map; import org.jdom.Document; import org.jdom.Element; import org.jdom.input.SAXBuilder; import org.jdom.xpath.XPath; public class ClassPathXmlApplicationContext implements BeanFactory { private Map<String, Object> container = new HashMap<String, Object>(); public ClassPathXmlApplicationContext(String fileName) throws Exception{ SAXBuilder sb = new SAXBuilder(); Document doc = sb.build(this.getClass().getClassLoader() .getResourceAsStream(fileName)); Element root = doc.getRootElement(); List list = XPath.selectNodes(root, "/beans/bean"); System.out.println(list.size()); for (int i = 0; i < list.size(); i++) { Element bean = (Element) list.get(i); String id = bean.getAttributeValue("id"); String clazz = bean.getAttributeValue("class"); Object o = Class.forName(clazz).newInstance(); container.put(id, o); System.out.println(id + " " + clazz); } } @Override public Object getBean(String id) { return container.get(id); } }
applicationContext.xml:
<?xml version="1.0" encoding="UTF-8"?> <beans> <bean id="v" class="com.bjsxt.spring.factory.Train"> </bean> <!-- //v=com.bjsxt.spring.factory.Car --> </beans>
Car:
package com.bjsxt.spring.factory; public class Car implements Moveable{ public void run() { System.out.println("car running......."); } }
Test测试类:
package com.bjsxt.spring.factory; import java.io.IOException; import java.util.Properties; public class Test { /** * @param args * @throws IOException */ public static void main(String[] args) throws Exception { BeanFactory f = new ClassPathXmlApplicationContext("com/bjsxt/spring/factory/applicationContext.xml"); Object o = f.getBean("v"); Moveable m = (Moveable)o; m.run(); } }