工厂模式
个人博客,想要搭建个人博客的可以进来看看: http://www.ioqian.top/
工厂方法模式,定义了一个创建对象的接口,单由于子类决定要实例化的类是哪一个。工厂方法把实例化推迟到子类
抽象工厂模式,提供了一个接口,用于创建相关或依赖对象的家族,而不需要明确指定具体类
设计模式系列源码: https://github.com/liloqian/DesiginModeDemo
背景 , 我们是披萨厂家,要给我们的客户提供一个订餐系统,可以预定我们各种各样的披萨(捞蛤披萨,奶酪披萨),各地的披萨(北京的,西安的),需要注意的是,西安的奶酪披萨和北京的奶酪披萨不同,捞蛤的也不同…
1.普通想法
public class NoFactory {
//type为披萨类型
private static Pizza orderPizza(String type){
Pizza pizza = null;
//if .. else if... 但是披萨的类型是一直在改变增加,所以我们要引用工厂模式
if(type.equalsIgnoreCase("cheesepizza")){
pizza = new CheesePizza();
}else if(type.equalsIgnoreCase("clampizza")){
pizza = new ClamPizza();
}
return pizza;
}
public static void main(String[] args) {
//我们点了一份奶酪披萨
Pizza pizza = orderPizza("cheesepizza");//这部分变化的放入工厂中
pizza.prepare();
pizza.box();
}
}
code唯一不变的就是一直在变化,但是我们的披萨种类会一直增加,所以后边要一直改变if那部分代码,这样的设计是存在问题的。
2.简单工厂方式
简单工厂的目的,主要负责实现生产对象的细节,根据订单来生产。每一个商店有对应着自己的工厂。
/**pizza 的父类*/
public abstract class Pizza {
//每个pizza的准备方法不一样
public abstract void prepare();
public void box() {
System.out.println("box done ...");
}
}
/**奶酪披萨*/
public class CheesePizza extends Pizza {
@Override
public void prepare() {
System.out.println("prepare CheesePizza...");
}
}
/**捞蛤披萨*/
public class ClamPizza extends Pizza {
@Override
public void prepare() {
System.out.println("prepare ClamPizza...");
}
}
简单工厂类,仅仅负责生产不同的披萨
/**简单披萨工厂*/
public class SimpleFactory {
//就是把变化的部分提取出来放在这里,以后当需求改变时仅仅改变这个工厂方法就好了
public static Pizza createPizza(String type){
Pizza pizza = null;
if(type.equalsIgnoreCase("cheesepizza")){
pizza = new CheesePizza();
}else if(type.equalsIgnoreCase("clampizza")){
pizza = new ClamPizza();
}
return pizza;
}
}
披萨订餐系统
/**披萨订单系统*/
public class PizzaStore {
SimpleFactory factory;
//传入我们上面的简单工厂
public PizzaStore(SimpleFactory factory) {
this.factory = factory;
}
//预定披萨
public Pizza orderPizza(String type){
Pizza pizza;
pizza = factory.createPizza(type);
pizza.prepare();
pizza.box();
return pizza;
}
}
测试Main
public class Main {
public static void main(String[] args) {
PizzaStore store = new PizzaStore(new SimpleFactory());
store.orderPizza("cheesepizza");
System.out.println("---------------------------------------");
store.orderPizza("clampizza");
}
}
//结果
prepare CheesePizza...
box done ...
---------------------------------------
prepare ClamPizza...
box done ...
Process finished with exit code 0
上面是简单工厂的UML图,代码仅仅使用了Pizza类的Prepare()和box()方法,也仅仅实现了2个具体类,有说明意义就可以 ,上面的Pizza用抽象类实现的好处是不同的披萨中不同的操作可以留给子类实现;并且在PizzaStore使用Pizza的调用方法,可以不用关心到底是哪个具体的披萨,保证了在后面的变动中,仅仅只需要改变SimpleFactory就可以,PizzaStore代码完全不需要修改
3.工厂方法模式
这里就要引入不同地方的披萨,北京和西安的奶酪披萨是不一样的,所以我们的改变是不需要上面的简单工厂类,直接在PizzaStore中写一个抽象的
createPizza()方法,具体的实现留给不同地区的订餐系统来决定,各个地区的订餐系统都要继承这个PizzaStore
pizza类
public abstract class Pizza {
public abstract void prepare();
public void box() {
System.out.println("box done ...");
}
}
/**西安的奶酪披萨*/
public class XIANCheesePizza extends Pizza {
@Override
public void prepare() {
System.out.println("prepare xian-style cheesePizza");
}
}
/**北京的的奶酪披萨*/
public class BEIJINGCheesePizza extends Pizza {
@Override
public void prepare() {
System.out.println("prepare beijing-style cheesePizza");
}
}
订餐系统
/**订餐系统*/
public abstract class PizzaStore {
public void orderPizza(String type){
Pizza pizza ;
/**披萨的类型有子类去具体实现*/
pizza = createPizza(type);
pizza.prepare();
pizza.box();
}
public abstract Pizza createPizza(String type);
}
/**北京的订餐系统*/
public class BEIJINGPizzaStore extends PizzaStore {
/**返回的是北京口味的披萨*/
@Override
public Pizza createPizza(String type) {
Pizza pizza = null;
if(type.equalsIgnoreCase("cheesepizza")){
pizza = new BEIJINGCheesePizza();
}
return pizza;
}
}
/**西安订餐系统*/
public class XIANPizzaStore extends PizzaStore {
/**返回的是西安口味的披萨*/
@Override
public Pizza createPizza(String type) {
Pizza pizza = null;
if(type.equalsIgnoreCase("cheesepizza")){
pizza = new XIANCheesePizza();
}
return pizza;
}
}
测试Main
public class Main {
public static void main(String[] args) {
//背景订餐系统
PizzaStore beijing = new BEIJINGPizzaStore();
beijing.orderPizza("cheesepizza");
//西安订餐系统
PizzaStore xian = new XIANPizzaStore();
xian.orderPizza("cheesepizza");
}
}
//结果
prepare beijing-style cheesePizza //北京订餐系统得到的是北京的口味
box done ...
prepare xian-style cheesePizza
box done ...
Process finished with exit code 0
结合代码和上图
- Product ,对于我们的Pizza父类
- ConcreteProduct ,对于BEIJINGPizzaStore和XIANPizzaStore
- Creator PizzaStore父类 ,是一个抽象类,具体的实现让子类去做
- ConcreteCreator ,XIANPizzaStore金额BEIJINGPizzaStore
4.依赖倒置原则(Dependency Inversion Principle)
高层模块不应该依赖低层模块,二者都应该依赖其抽象;抽象不应该依赖细节;细节应该依赖抽象。结合我们的代码,就是在工厂模式中让PizzaStore依赖抽象的Pizza,各种具体的披萨类也依赖Pizza
几个指导方针帮助你遵循此原则:
- 变量不可以持有具体类的引用,如果使用new,就会持有具体类的引用,可以使用工厂来避开这样的做法。
- 不要让类派生自具体类,如果派生自具体类,就会依赖具体类。要派生自抽象类或接口
- 不要覆盖基类中已实现的方法 ,如果覆盖基类已实现的方法,那么基类不是一个真正适合被继承的抽象。基类中已实现的方法应该由所有的子类共享
5.抽象工厂模式 , 简单工厂模式 , 工厂模式的区别
推荐博客: http://blog.csdn.net/superbeck/article/details/4446177
三者的区别:
简单工厂 : 用来生产同一等级结构中的任意产品。(对于增加新的产品,无能为力)
工厂方法 :用来生产同一等级结构中的固定产品。(支持增加任意产品)
抽象工厂 :用来生产不同产品族的全部产品。(对于增加新的产品,无能为力;支持增加产品族)
抽象工厂和工厂方法的区别:
- 抽象工厂和工厂方法模式都是创建对象,但是抽象工厂用的是组合(多个抽象方法),工厂模式用的是继承(子类去实现功能)
- 抽象工厂把一群相关产品集合起来
- 抽象工厂经常使用工厂方法来创建他的多个产品
6.总结
1.所有的工厂都是用来封装对象的创建
2.简单工厂,虽然不是一个真正的设计模式,但仍然是一个简单的方法,可以将客户程序从具体类中解耦
3.工厂方法使用继承,把对象的创建委托给子类,子类实现工厂方法创建对象
4.抽象工厂使用组合,对象的创建被实现在工厂接口所暴露的方法中
5.所以的工厂模式都通过减少应用程序和具体类之间的依赖促进松耦合
6.工厂是很有威力的技巧,帮助我们针对抽象编程,不对具体实现编程