简单工厂

简单工厂其实不是一种“真正的”设计模式,而更像是一种编程习惯。

1
2
3
4
5
6
7
8
9
10
11
12
pulic class SimplePizzaFactory {
public Pizza createPizza(String type) {
Pizza pizza = null;
if(type.equals("cheese")) {
pizza = new CheesePizza();
} else if(type.equals("pepperoni")) {
pizza = new PepperoniPizza();
} else if(type.equals("clam")) {
pizza = new ClamPizza();
}
return pizza;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public class PizzaStore {
SimplePizzaFactory factory;
public PizzaStore(SimplePizzaFactory factory) {
this.factory = factory;
}
//制作流程对于加盟店没有约束
public Pizza orderPizza(String type) {
Pizza pizza;
pizza = factory.createPizza(type);
pizza.prepare();
pizza.bake();
pizza.cut();
pizza.box();
return pizza;
}
//其它方法
}

工厂不同,制作出来披萨的各种口味又不同

1
2
3
4
5
NYPizzaFactory nyFactory = new NYPizzaFactory();
PizzaStore nyStore = new PizzaStore(nyFactory);
nyStore.orderPizza("veggie");
ChicagoPizzaFactory chicagoFactory = new ChicagoPizzaFactory(zzaStore chicagoStore = new PizzaStore(chicagoFactory);
chicagoStore.orderPizza("veggie");

工厂方法

  原来是一个对象负责所有具体类的实现,现在通过PizzaStore做一些转变,变成一群子类来负责实例化。也就是,虽然现在大致流程已经定下来了,但是如果加盟店之前就已经有过做Pizza的经验,并有一个独特的配方,而现在的Pizza是全部从工厂里面制作出来的,那么我们就需要挨个去所有工厂,通知它们修改、新增产品。怎么才能保持现状,让加盟店不失去自己的特点呢?我们的解决方法是将createPizza()方法下放到PizzaStore中。

原本是由一个对象负责所有具体类的实例化,现在通过PizzaStore做一些转变,变成由一群子类负责实例化。

创造一个新的PizzaStore模板:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
public abstract PizzaStore {
/**
* 工厂方法是抽象的,所以依赖子类处理对象
* 工厂方法必须返回一个产品,超类中定义的方法,通常使用到工厂方法的返回值
* 工厂方法将客户(也就是超类中的代码,比如orderPizza())和实际创建具体产品分隔开来
* 工厂方法可能需要参数,也可能不需要参数来生产产品
*/
public abstract Pizza createPizza(String type);
public final Pizza orderPizza(String type) {
Pizza pizza;
pizza = createPizza(type);
pizza.prepare();
pizza.bake();
pizza.cut();
pizza.box();
return pizza;
}
}

  实例化比萨的责任被移到一个方法当中,这个方法就如同“工厂”,称为工厂方法

  工厂方法用来处理对象的创建,并将这样的行为封装在子类中。这样,客户程序中关于超类的代码就和子类对象创建代码解耦了。

具体工厂类:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
//生产Pizza通过工厂方法来实现的
//工厂方法针对每一种产品提供一个工厂类。通过不同的工厂实例来创建不同的产品实例
public class NYPizzaStore extends PizzaStore {
public Pizza createPizza(String type) {
if(type.equals("cheese")) {
return new NYStyleCheesePizza();
} else if(type.equals("pepperoni")) {
return new NYStylePepperoniPizza();
} else if(type.equals("clam")) {
return new NYStyleClamPizza();
} else {
return null;
}
}
}

比萨类本身的实现:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
import java.util.ArrayList;
public abstract class Pizza {
String name;
String dough;
String sauce;
ArrayList toppings = new ArrayList();
//这里面提供了制作步骤
void prepare() {
System.out.println("Preparing " + name);
System.out.println("Tossing dough...");
System.out.println("Adding sauce...");
System.out.println("Adding toppings: ");
for(int i=0;i<toppings.size();i++) {
System.out.println(" " + toppings.get(i));
}
}

void bake() {
System.out.println("Bake for 25 minutes at 350");
}

void cut() {
System.out.println("Cutting the pizza into diagonal slices");
}

void box() {
System.out.println("Place pizza in official PizzaStore box");
}
public String getName() {
return name;
}
}

具体定制一个比萨:

1
2
3
4
5
6
7
8
9
public class NYStyleCheesePizza extends Pizza {
public NYStyleCheesePizza() {
name = "NY Style Sauce and Cheese Pizza";
dough = "Thin Crust Dough";
sauce = "Marinara Sauce";

toppings.add("Grated Reggiano Cheese");
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
public class ChicagoStyleCheesePizza extends Pizza {
public ChicagoStyleCheesePizza() {
name = "Chicago Style Deep Dish Cheese Pizza";
dough = "Extra Thick Crust Dough";
sauce = "Plum Tomato Sauce";

toppings.add("Shredded Mozzarella Cheese");
}

void cut() {
System.out.println("Cutting the pizza into square slices");
}
}

工厂方法模式

  工厂方法模式定义了一个创建对象的接口,但由子类决定要实例化的类是哪一个。工厂方法让类把实例化推迟到子类。

抽象工厂(Creator)角色:工厂方法模式的核心

具体工厂(ConcreteCreator)角色:担任这个角色的是实现了抽象工厂接口的具体Java类

抽象产品(AbstractProduct)角色:工厂方法模式所创建的对象的超类型

具体产品(ConcreteProduct)角色:这个角色实现了抽象产品角色所声明的接口,顾名思义

工厂方法的子类看起来很像简单工厂,但他们却不一样。简单工厂把全部的事情,在一个地方都处理完了(运行时无法进行修改),然而工厂方法却是创建一个框架,让子类决定要如何实现。比方说,在工厂方法中,orderPizza()方法提供了一半的框架,以便创建比萨,orderPizza()方法依赖工厂方法创建具体类,并制造出实际的比萨。通过继承PizzaStore类,决定实际制造出的比萨是什么。简单工厂的做法,可以将对象的创建封装起来,但是简单工厂不具备工厂方法的弹性,因为简单工厂不能变更正在创建的产品。

设计原则——依赖倒置原则

  要依赖抽象,不要依赖具体类。这个原则说明了:不能让高层组件依赖底层组件,而且不管高层或底层组件,“两者”都应该依赖于抽象。

  现在考虑这两种情况。非常依赖披萨店的主要问题在于:它依赖每个披萨类型。因为它是在自己的orderPizza()方法中,实例化这些具体类型的。

几个原则,避免在OO设计中违反依赖倒置原则:

  • 变量不可以持有具体类的引用
  • 不要让类派生自具体类
  • 不要覆盖基类中已实现的方法

  在添加新产品(注意这个新产品不是同一等级的新产品)时,需要编写新的具体产品类,而且还要提供与之对应的具体工厂类,系统中类的个数将成对增加,在一定程度上增加了系统的复杂度,有更多的类需要编译和运行,会给系统带来一些额外的开销。

抽象工厂模式

  对于工厂方法模式, 用来生产同一等级结构中的固定产品。支持增加任意产品,新增产品时不需要更改已有的工厂了。但是当我们想要增加一种新品时,我们就需要新开一条新的生产线,可以理解为我们需要再去重新买配料什么的,只用来生产这一个新品。但是,这样就浪费太多配料,效率也不高。或者说,我们店里面可以做很多种Pizza,但是每一种Pizza都有自己对应的那一些料,就算这种Pizza的面粉别的同样可以用,但是在工厂模式里面,这些面粉别的就是不给用。那这样的话,我们就浪费了很多资源。所以,我们要告诉店员,这些配料是可以通用的。配料可以通用的模式就是我们所说的抽象工厂方法了

  • 抽象工厂(AbstractFactory)角色:担任这个角色的是抽象工厂模式的核心,是与应用系统的商业逻辑无关的

  • 具体工厂(ConcreteFactory)角色:这个角色直接在客户端的调用下创建产品的实例

  • 抽象产品(AbstractProduct)角色:担任这个角色的类是抽象工厂模式所创建的对象的父类,或它们共同拥有的接口

  • 具体产品(Product)角色:抽象工厂模式所创建的任何产品对象都是一个具体的产品类的实例。这是客户端最终需要的东西

与工厂方法模式不同的是,抽象工厂模式中的具体工厂不再是只能创建一种产品(也就是一类的产品,同一类的产品),一个具体的工厂可以创建一个产品族的产品。

回到现在的Pizza店

现在,随着我们经营范围的扩大,我们不再只是单单制作Pizza了,我们还聘请了甜点师来制作甜点。同样,不同地区的人们喜欢的甜点也是不同的。那么在我们现在的PizzaStore除了createPizza方法之外,还有createCoke方法。每一家加盟店都提供给顾客这两类食物。

抽象工厂模式提供一个接口,用于创建相关或依赖对象的家族,而不需要明确指定具体类。

我们注意到,抽象工厂的每个方法实际上看起来都像工厂方法。每个方法能被声明称抽象,而子类的方法覆盖这些方法来创建某些对象。

所以,抽象工厂方法经常以工厂方法的方式实现,这很有道理,对吧?抽象工厂的任务是定一个负责创建一组产品的接口。这个接口内的每个方法负责创建一个具体产品,同时我们利用实现抽象工厂的子类来提供这些具体的做法。所以,在抽象工厂中利用工厂方法实现生产方法是相当自然的做法。

再举一个抽象工厂的例子

步骤 1

为形状创建一个接口。Shape.java

1
public interface Shape {    void draw(); }

步骤 2

创建实现接口的实体类。Rectangle.java

1
2
3
4
5
6
public class Rectangle implements Shape {
@Override
public void draw() {
System.out.println("Inside Rectangle::draw() method.");
}
}

Square.java

1
2
3
4
5
6
public class Square implements Shape {      
@Override
public void draw() {
System.out.println("Inside Square::draw() method.");
}
}

Circle.java

1
2
3
4
5
6
public class Circle implements Shape {
@Override
public void draw() {
System.out.println("Inside Circle::draw() method.");
}
}

步骤 3

为颜色创建一个接口。

Color.java

1
2
3
public interface Color {    
void fill();
}

步骤4

创建实现接口的实体类。

Red.java

1
2
3
4
5
6
public class Red implements Color {      
@Override
public void fill() {
System.out.println("Inside Red::fill() method.");
}
}

Green.java

1
2
3
4
5
6
public class Green implements Color {      
@Override
public void fill() {
System.out.println("Inside Green::fill() method.");
}
}

Blue.java

1
2
3
4
5
6
public class Blue implements Color {      
@Override
public void fill() {
System.out.println("Inside Blue::fill() method.");
}
}

步骤 5

为 Color 和 Shape 对象创建抽象类来获取工厂。

AbstractFactory.java

1
2
3
4
public abstract class AbstractFactory {    
public abstract Color getColor(String color);
public abstract Shape getShape(String shape);
}

步骤 6

创建扩展了 AbstractFactory 的工厂类,基于给定的信息生成实体类的对象。

ShapeFactory.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
public class ShapeFactory extends AbstractFactory {         
@Override
public Shape getShape(String shapeType){
if(shapeType == null){
return null;
}
if(shapeType.equalsIgnoreCase("CIRCLE")){
return new Circle();
} else if(shapeType.equalsIgnoreCase("RECTANGLE")){
return new Rectangle();
} else if(shapeType.equalsIgnoreCase("SQUARE")){
return new Square();
}
return null;
}
@Override
public Color getColor(String color) {
return null;
}
}

ColorFactory.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
public class ColorFactory extends AbstractFactory {         
@Override
public Shape getShape(String shapeType){
return null;
}
@Override
public Color getColor(String color) {
if(color == null){
return null;
}
if(color.equalsIgnoreCase("RED")){
return new Red();
} else if(color.equalsIgnoreCase("GREEN")){
return new Green();
} else if(color.equalsIgnoreCase("BLUE")){
return new Blue();
}
return null;
}
}

步骤 7

创建一个工厂创造器/生成器类,通过传递形状或颜色信息来获取工厂。

FactoryProducer.java

1
2
3
4
5
6
7
8
9
10
public class FactoryProducer {    
public static AbstractFactory getFactory(String choice){
if(choice.equalsIgnoreCase("SHAPE")){
return new ShapeFactory();
} else if(choice.equalsIgnoreCase("COLOR")){
return new ColorFactory();
}
return null;
}
}

步骤 8

使用 FactoryProducer 来获取 AbstractFactory,通过传递类型信息来获取实体类的对象。

AbstractFactoryPatternDemo.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
public class AbstractFactoryPatternDemo {    
public static void main(String[] args) {
//获取形状工厂
AbstractFactory shapeFactory = FactoryProducer.getFactory("SHAPE");
//获取形状为 Circle 的对象
Shape shape1 = shapeFactory.getShape("CIRCLE");
//调用 Circle 的 draw 方法
shape1.draw();
//获取形状为 Rectangle 的对象
Shape shape2 = shapeFactory.getShape("RECTANGLE");
//调用 Rectangle 的 draw 方法
shape2.draw();
//获取形状为 Square 的对象
Shape shape3 = shapeFactory.getShape("SQUARE");
//调用 Square 的 draw 方法
shape3.draw();
//获取颜色工厂
AbstractFactory colorFactory = FactoryProducer.getFactory("COLOR");
//获取颜色为 Red 的对象
Color color1 = colorFactory.getColor("RED");
//调用 Red 的 fill 方法
color1.fill();
//获取颜色为 Green 的对象
Color color2 = colorFactory.getColor("Green");
//调用 Green 的 fill 方法
color2.fill();
//获取颜色为 Blue 的对象
Color color3 = colorFactory.getColor("BLUE");
//调用 Blue 的 fill 方法
color3.fill();
}
}

步骤 9

执行程序,输出结果:

1
2
3
4
5
6
Inside Circle::draw() method.
Inside Rectangle::draw() method.
Inside Square::draw() method.
Inside Red::fill() method.
Inside Green::fill() method.
Inside Blue::fill() method.
联系我

评论