2_工厂方法

写在前面:设计模式不是干掉变化,而是让变化集中到一个区域,方便开发。

 工厂方法的核心思想就是自己不直接”new”对象,而是通过发送一些信息,问其他对象要。举个例子:有个商贸市场,用”new”的方式就是类似把生产基地建设在商贸市场里面,客户要什么,就生产什么。而通过工厂方法就是把工厂搬出去,我只要根据用户需求提交订单向工厂即可。

这样商贸市场就只需要做两个动作,接收用户请求和提交订单。把变化“赶”到了用户和工厂那里,添加商品只要添加对应的工厂即可,用户的需求改变只需要用户改变订单内容即可。

 

先看代码一(工厂在商贸市场里面):

 

public class MainTest {
    public static void main(String[] args) {
		//用户
    	Market market = new Market();
		market.consume();
	}
}

class Market {
	private IClothes clothes;
	void consume() {
		clothes = new Jacket();// 1
		clothes.produce();
	}
}

interface IClothes {
	void produce();
}

class Hat implements IClothes {
	public void produce() {
		System.out.println("生产帽子");
	}
}

class Jacket implements IClothes {
	public void produce() {
		System.out.println("生产夹克");
	}
}

class Pants implements IClothes {
	public void produce() {
		System.out.println("生产裤子");
	}
}

这里的问题:1、工厂的商品改变,商贸市场需要改变(工厂改变名字了,注释1处就需要改变);2、用户的需求改变,商贸市场需要改变,(客户要另外的衣服、注释1处就需要改变)。

这里可以看出每个变化都会引起商贸市场需要改变,究其原因就是:产生这个问题的原因而且Market和Jacket是编译依赖,是硬编码。为了解决这个问题引入了Factory,把商贸市场生产衣服的功能搬出去。看下面的代码二(工厂独立出去,按照订单,单独生产):

 

public class MainTest {
    public static void main(String[] args) {
        //用户
		Market market = new Market();
		market.consume("hat");
	}
}

class Market {
	
	private Factory factory = new Factory();
	
	void consume(String target) {
		IClothes clothes = factory.getInstance(target);// 1
		clothes.produce();
	}
}

class Factory {
    public IClothes getInstance(String target) { // 2
    	if ("hat".equals(target)) {
			return new Hat();
		} else if ("jacket".equals(target)) {
			return new Jacket();
		} else if ("pants".equals(target)) {
			return new Pants();
		}
		return null;
	}
}

//IClothes, Hat, Jacket, Pants 同上,省略

商贸市场里面只有工厂,用户提交的订单是产品的信息(工厂的标志信息),商贸市场直接把订单交给工厂,工厂生产对应的商品。这样一来,商贸市场就不变了,添加商品只需要修改工厂,用户要换商品,只需要换订单号即可,这样的好处就是每次变化只需要改变一个对象即可,商贸市场不用变了。

但是这种方法还是有不爽的地方,就是我需要添加或者删除一种商品的时候,必须修改Factory类中的if-else语句,从面向对象的角度来说这是硬编码。而干掉这种类型硬编码的方式就是多态,请看代码三(工厂多态化)

 

public class MainTest {
    public static void main(String[] args) {
    	//用户
		IFactory factory = new HatFactory();
    	Market market = new Market(factory);
		market.consume();
	}
}

class Market {
	
	private IFactory factory;
	
	public Market(IFactory factory) {
        this.factory = factory;
	}
	
	void consume() {
		IClothes clothes = factory.getInstance();// 1
		clothes.produce();
	}
}

interface IFactory {
    IClothes getInstance();
}

class HatFactory implements IFactory {
	public IClothes getInstance() {
		return new Hat();
	}
}

class JacketFactory implements IFactory {
	public IClothes getInstance() {
		return new Jacket();
	}
}

class PantsFactory implements IFactory {
	public IClothes getInstance() {
		return new Pants();
	}
}
//IClothes, Hat, Jacket, Pants 同上,省略


这里我们可以看出和代码二中的区别就是工厂从选择化变成了多态化,用户订单信息就是对应工厂的信息,不需要再去选择一遍,Factory类变成了一个接口IFactory,每个商品只需要去实现这个接口就可以了,减轻了商品的增加对代码带来的影响。其他的特性与代码二中的方式并无区别。

 

下面来看一下Spring中的一个工厂方法的应用,在这里,需要解决这几个问题:

1、 用户的订单内容是什么?

2、 工厂怎么创建对应的对象的?

3、 工厂怎么根据用户的订单知道用户的内容?

 

对于问题一:用户的订单内容是什么?这个问题不难,用过Spring的都知道,就是那个配置文件的applicationContext.xml中配置的那个引用id。

 

<bean id="test" class="edu.swust.job.spring.aop.AOPTest"/>
AOPTest test = context.getBean("test", AOPTest.class);

对于问题二:工厂怎么创建对应的对象的?就是applicationContext.xml中每个<bean></bean>都有一个class属性,里面是对应类的全限定名,知道全限定名之后就可以通过反射生成对象实例即可。

对于问题三:工厂怎么根据用户的订单知道用户的内容?在Spring中运用了类似代码二中的方法,只是它没有用if-else,它用的Map<String,Object>,String是引用id,Object是对应class属性反射生成的对象。

/** Cache of shareable singleton objects: bean name --> bean instance */
private final Map<String, Object> singletonObjects = new HashMap<String, Object>();

在这里需要注意单例与多例的区别。单例:在Map中查询对应的引用id,如果有,直接return出Map中对应的value;如果没有,根据读取的配置文件中引用id的class属性,反射生成一个对象实例,并把生成的引用id和对象实例put到Map中,再把刚生成的实例return出来。多例:根据读取的配置文件中引用id的class属性,反射生成一个对象实例并return出来即可。


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值