本文示例代码材料源自Head First设计模式
以前整理自己整理的链接:
工厂模式
https://blog.csdn.net/u011109881/article/details/56541580
抽象工厂
https://blog.csdn.net/u011109881/article/details/56730497
实例
假设现在要生产各种各样的Pizza,Pizza有不同的原料,就可以做出不同的Pizza,Pizza需要经过材料准备 烘焙 切片 打包等诸多过程。
没有学习设计模式之前,我们的代码可能是这样的:
public class PizzaStore {
Pizza orderPizza(String type) {
Pizza pizza;
switch (type) {
case "cheese":
pizza = new CheesePizza();
break;
case "greek":
pizza = new GreekPizza();
break;
default:
pizza = new CheesePizza();
break;
}
pizza.prepare();
pizza.bake();
pizza.cut();
pizza.box();
return pizza;
}
}
public class Pizza {
public void prepare(){
System.out.println("prepare");
};
public void bake(){
System.out.println("bake");
};
public void cut(){
System.out.println("cut");
};
public void box(){
System.out.println("box");
};
}
但是请思考一下,这样的代码易于扩展么?
比如我们要新加几种Pizza,原先的Pizza由于销量不好全部下架。那么我们只好进入orderPizza内部,对其进行一次“大手术”,而这违反了设计原则的对修改关闭对扩展开放的原则。
使用简单工厂(不算设计模式 只能算技巧)
我们再分析一下orderPizza的代码,可以发现生产Pizza的部分可能会经常变动,而包装过程不怎么变动。那么我们可不可以将变化的部分抽出来呢?
简单工厂类图
把变化的部分抽离出来,就是利用了简单工厂的思想。它的结构如下:
public class SimplePizzaFactory {
public Pizza createPizza(String type){
Pizza pizza;
switch (type) {
case "cheese":
pizza = new CheesePizza();
break;
case "greek":
pizza = new GreekPizza();
break;
default:
pizza = new CheesePizza();
break;
}
return pizza;
}
}
public class PizzaStore {
SimplePizzaFactory factory;
public PizzaStore(SimplePizzaFactory factory) {
this.factory = factory;
}
Pizza orderPizza(String type) {
Pizza pizza;
pizza = factory.createPizza(type);
pizza.prepare();
pizza.bake();
pizza.cut();
pizza.box();
return pizza;
}
}
聪明的读者也许一下子就会发现问题:这丫的不是自欺欺人掩耳盗铃么。没错,你是把变化的部分抽离了,放到了SimplePizzaFactory里面,但是这不过是把问题从一个地方转移到另一个地方么?问题仍然存在啊?
其实这样做有利于复用SimplePizzaFactory的代码,比如其他使用者需要对Pizza进行不同的加工。比如在门店购买的Pizza和饿了么送货的Pizza的处理应该不会相同。这样既分离了变化和不变的部分,又达成代码复用的目的。
在上面这个例子中PizzaStore中组合了SimplePizzaFactory对象,SimplePizzaFactory对象则组合了Pizza对象,Pizza对象又是各类Pizza的基类。简单工厂就是利用组合方式来分离变化与不变的部分的。
引入地域风情
现在,Pizza连锁店生意兴隆,风靡全国各地。比如上海苏州的Pizza会偏甜,湖南重庆的Pizza可能会放辣椒。
对于这种新加的元素,可以使用工厂模式。
使用工厂模式
类图:
(由于ProcessOn不能实现单个方法斜体,因此将抽象方法前面加上< A >表示抽象方法)
工厂模式代码实例
创建者类(creator)
public abstract class PizzaStore {
Pizza pizza;
public PizzaStore() {
}
public Pizza orderPizza(String type) {
pizza = createPizza(type);
pizza.prepare();
pizza.bake();
pizza.cut();
pizza.box();
return pizza;
}
public abstract Pizza createPizza(String type);
}
public class CQPizzaStore extends PizzaStore{
public CQPizzaStore() {
}
@Override
public Pizza createPizza(String type) {
switch (type) {
case "cheese":
pizza = new CQCheesePizza();
break;
case "greek":
pizza = new CQGreekPizza();
break;
default:
pizza = new CQCheesePizza();
break;
}
return pizza;
}
}
public class SHPizzaStore extends PizzaStore{
public SHPizzaStore() {
}
@Override
public Pizza createPizza(String type) {
switch (type) {
case "cheese":
pizza = new SHCheesePizza();
break;
case "greek":
pizza = new SHGreekPizza();
break;
default:
pizza = new SHCheesePizza();
break;
}
return pizza;
}
}
产品类
public abstract class Pizza {
String name;
String dough;
String sauce;
ArrayList<String> toppings = new ArrayList<String>();
public void prepare(){
System.out.println("prepare "+ name);
System.out.println("prepare Tossing "+dough);
System.out.println("prepare Adding"+ sauce);
System.out.println("prepare Adding toppings:");
for(int i=0;i<toppings.size();i++){
System.out.println(" "+toppings.get(i));
}
};
public void bake(){
System.out.println("bake");
};
public void cut(){
System.out.println("cut");
};
public void box(){
System.out.println("box");
};
public String getName(){
return name;
}
}
public class CQCheesePizza extends Pizza{
public CQCheesePizza(){
name = "CQ Style Sauce and Cheese Pizza";
dough = "Extar Thick Crust Dugh";
sauce ="Plum Tomato Sauce";
toppings.add("老干妈");
}
}
public class CQGreekPizza extends Pizza{
public CQGreekPizza(){
name = "CQ Style Sauce and Greek Pizza";
dough = "Extar Thick Crust Dugh";
sauce ="Plum Tomato Sauce";
toppings.add("老干妈");
}
}
public class SHCheesePizza extends Pizza{
public SHCheesePizza(){
name = "SH Style Sauce and CHeese Pizza";
dough = "Thin Crust Dugh";
sauce ="Marinar Sauce";
toppings.add("甜酱");
}
}
public class SHGreekPizza extends Pizza{
public SHGreekPizza(){
name = "SH Style Sauce and Greek Pizza";
dough = "Thin Crust Dugh";
sauce ="Marinar Sauce";
toppings.add("甜酱");
}
}
测试类
public class Test {
public static void main(String[] args) {
PizzaStore store = new CQPizzaStore();
CQCheesePizza cqCheese = (CQCheesePizza) store.orderPizza("cheese");
System.out.println();
CQGreekPizza cqGreek = (CQGreekPizza) store.orderPizza("greek");
System.out.println();
store = new SHPizzaStore();
SHCheesePizza shCheese = (SHCheesePizza) store.orderPizza("cheese");
System.out.println();
SHGreekPizza shGreek = (SHGreekPizza) store.orderPizza("greek");
System.out.println();
}
}
测试结果:
prepare CQ Style Sauce and Cheese Pizza
prepare Tossing Extar Thick Crust Dugh
prepare AddingPlum Tomato Sauce
prepare Adding toppings:
老干妈
bake
cut
box
prepare CQ Style Sauce and Greek Pizza
prepare Tossing Extar Thick Crust Dugh
prepare AddingPlum Tomato Sauce
prepare Adding toppings:
老干妈
bake
cut
box
prepare SH Style Sauce and CHeese Pizza
prepare Tossing Thin Crust Dugh
prepare AddingMarinar Sauce
prepare Adding toppings:
甜酱
bake
cut
box
prepare SH Style Sauce and Greek Pizza
prepare Tossing Thin Crust Dugh
prepare AddingMarinar Sauce
prepare Adding toppings:
甜酱
bake
cut
box
使用抽象工厂模式
抽象工厂模式类图
代码示例
原料基类
public class Cheese {
}
public class Clams {
}
public class Dough {
}
public class Pepperoni {
}
public class Sauce {
}
public class Veggies {
}
原料实体类(部分略)
public class PepperyCheese extends Cheese {
}
public class PepperyClam extends Clams{
}
public class PepperyDough extends Dough {
}
public class PepperyPepperoni extends Pepperoni {
}
public class PepperySauce extends Sauce {
}
public class RedPepper extends Veggies {
}
原料工厂类
public interface PizzaIngedientFactory {
public Dough createDough();
public Clams createClams();
public Cheese createCheese();
public Pepperoni createPepperoni();
public Sauce createSauce();
public Veggies[] createVeggies();
}
public class NYPizzaIngedientFactory implements PizzaIngedientFactory {
@Override
public Dough createDough() {
System.out.println("createDough");
return new ThinCrustDough();
}
@Override
public Clams createClams() {
System.out.println("createClams");
return new FreshClam();
}
@Override
public Cheese createCheese() {
System.out.println("createCheese");
return new ReggianoCheese();
}
@Override
public Pepperoni createPepperoni() {
System.out.println("createPepperoni");
return new SlicedPepperoni();
}
@Override
public Sauce createSauce() {
System.out.println("createSauce");
return new MarinaraSauce();
}
@Override
public Veggies [] createVeggies() {
System.out.println("createVeggies");
Veggies veggies [] = {new Garlic() , new Onion(),new Mushroom(),new RedPepper()};
return veggies;
}
}
public class CQPizzaIngedientFactory implements PizzaIngedientFactory {
@Override
public Dough createDough() {
System.out.println("createDough PepperyDough");
return new PepperyDough();
}
@Override
public Clams createClams() {
System.out.println("createClams PepperyClam");
return new PepperyClam();
}
@Override
public Cheese createCheese() {
System.out.println("createCheese PepperyCheese");
return new PepperyCheese();
}
@Override
public Pepperoni createPepperoni() {
System.out.println("createPepperoni PepperyPepperoni");
return new PepperyPepperoni();
}
@Override
public Sauce createSauce() {
System.out.println("createSauce PepperySauce");
return new PepperySauce();
}
@Override
public Veggies [] createVeggies() {
System.out.println("createVeggies");
Veggies veggies [] = {new Garlic() , new Onion(),new Mushroom(),new RedPepper()};
return veggies;
}
}
Pizza类
public abstract class Pizza {
String name;
Dough dough;
Sauce sauce;
Cheese cheese;
Clams clam;
ArrayList<Veggies> veggies = new ArrayList<Veggies>();
PizzaIngedientFactory ingedientFactory;
public abstract void prepare();
public void bake(){
System.out.println("bake");
};
public void cut(){
System.out.println("cut");
};
public void box(){
System.out.println("box");
};
public void setName(String name){
this.name = name;
}
public String getName(){
return name;
}
@Override
public String toString() {
return name;
}
}
public class CheesePizza extends Pizza {
public CheesePizza(PizzaIngedientFactory ingedientFactory){
this.ingedientFactory = ingedientFactory;
}
@Override
public void prepare() {
System.out.println("Preparing "+name);
dough = ingedientFactory.createDough();
sauce = ingedientFactory.createSauce();
cheese = ingedientFactory.createCheese();
}
}
public class ClamPizza extends Pizza {
public ClamPizza(PizzaIngedientFactory ingedientFactory){
this.ingedientFactory = ingedientFactory;
}
@Override
public void prepare() {
System.out.println("Preparing "+name);
dough = ingedientFactory.createDough();
sauce = ingedientFactory.createSauce();
cheese = ingedientFactory.createCheese();
clam = ingedientFactory.createClams();
}
}
店铺类
public abstract class PizzaStore {
Pizza pizza;
public PizzaStore() {
}
public Pizza orderPizza(String type) {
pizza = createPizza(type);
pizza.prepare();
pizza.bake();
pizza.cut();
pizza.box();
return pizza;
}
public abstract Pizza createPizza(String type);
}
public class CQPizzaStore extends PizzaStore{
@Override
public Pizza createPizza(String type) {
PizzaIngedientFactory cqPizzaIngedientFactory = new CQPizzaIngedientFactory();
switch (type) {
case "cheese":
pizza = new CheesePizza(cqPizzaIngedientFactory);
pizza.setName("CQ cheese Pizza");
break;
case "clam":
pizza = new ClamPizza(cqPizzaIngedientFactory);
pizza.setName("CQ clam Pizza");
break;
}
return pizza;
}
}
public class NYPizzaStore extends PizzaStore{
@Override
public Pizza createPizza(String type) {
PizzaIngedientFactory nyPizzaIngedientFactory = new NYPizzaIngedientFactory();
switch (type) {
case "cheese":
pizza = new CheesePizza(nyPizzaIngedientFactory);
pizza.setName("NY cheese Pizza");
break;
case "clam":
pizza = new ClamPizza(nyPizzaIngedientFactory);
pizza.setName("NY clam Pizza");
break;
}
return pizza;
}
}
测试类
public class Test {
public static void main(String[] args) {
PizzaStore store = new NYPizzaStore();
CheesePizza nyCheesePizza = (CheesePizza) store.orderPizza("cheese");
System.out.println();
ClamPizza nyClamPizza = (ClamPizza) store.orderPizza("clam");
System.out.println();
PizzaStore store2 = new CQPizzaStore();
CheesePizza cqCheesePizza = (CheesePizza) store2.orderPizza("cheese");
System.out.println();
ClamPizza cqClamPizza = (ClamPizza) store2.orderPizza("clam");
System.out.println();
}
}
关于工厂模式和抽象工厂模式的区别和联系
从上述工厂模式和抽象工厂模式的UML类图来看,其实工厂模式是存在于抽象工厂模式里面的。注意看如下共通部分:
工厂模式截图
抽象工厂模式部分截图
两种模式都是通过PizzaStore来生产产品。只不过,抽象工厂模式更为复杂一些。因为,它包含了一系列的产品原料,它更适合于生产零件很多,不同搭配可以生产不同产品的情况。
另外,这两种模式都包含生产对象的方法(本例中是createPizza方法),子类只要继承并实现该方法,就可以生产对象了,因此他们都是用于生产对象的模式,只不过抽象工厂模式中间加入了一个工厂来生成对象,他们将需要产品的客户端(本例中为测试类)与实际产品(本例中是Pizza)解耦。
所以工厂模式和抽象工厂模式还是很像的,区别相对较小。