当有一堆对象等着被实例化,究竟实现哪个类,需要在运行时由一些条件来决定!
如果代码是针对接口编写的,那么通过多态的特性,它就能与任何新的实现类进行绑定,从而实现扩展!
找出会变化的地方,把它们从不变的部分分离出来,单独进行设计!
工厂方法研究:
如何将实例化具体类的代码从应用中抽离,或者封装起来,使它们不会干扰其它部分。
每当需求发生变化或者有新的需求时,你必须对原来的代码进行修改才能完成对需求的实现,如果是这样的话,你应该意识到:你的系统在设计上存在严重问题!!!
对修改没关闭,对扩展没开放,3个字--->烂透了!
将创建对象的代码封装到一个对象中,这个对象就叫做工厂!
工厂模式的几种变体(所有的工厂模式都是用来封装对象的创建)
静态工厂
定义外部类Factory,并提供静态方法调用,返回对象
简单工厂
定义外部类Factory,使用者需要组合Factory到类中,再委托Factory对象去调用自己的方法返回对象
工厂方法
父类定义一个抽象的方法(该方法在框架中被调用),让子类去重写并决定返回对象的类型
工厂方法模式
定义了一个创建对象的接口(实为一个抽象方法),但由子类决定要实例化的类是哪一个。
工厂方法让类的实例化推迟到子类中进行。
抽象工厂
通过接口定义一个抽象的顶层工厂,子类为一系列不同的具体工厂
通过抽象工厂中定义好的接口,创建一个产品家族。
所有的工厂都是用来封装对象的创建
简单工厂,虽然不是真正的设计模式,但仍不失为一个简单的方法,可以将客户程序从具体类中解耦
工厂方法使用继承,把对象的创建委托给子类,子类实现工厂方法来创建对象
抽象工厂使用对象组合,对象的创建被实现在工厂接口所暴露出来的方法中
所有工厂模式都通过减少应用程序和具体类之间的依赖促进松耦合
工厂方法允许类将实例化延迟到子类中进行
抽象工厂创建相关的对象家族,而不需要依赖它们的具体类
依赖倒置原则,指导我们避免依赖具体类型,而要尽量依赖抽象
=======================================================================
静态工厂(比较常用,因为简单)
好处:不需要创建对象
缺点:不能通过继承来改变方法的行为,几乎不能扩展(已将静态调用写死在代码里)
package staticfactory;
/**
* 各种Pizza的基类
*
*/
public abstract class Pizza {
public void makePizza() {
this.prepare();
this.bake();
this.cut();
this.box();
}
abstract void prepare();
abstract void bake();
abstract void cut();
abstract void box();
}
package staticfactory;
public class CheesePizza extends Pizza {
@Override
void prepare() {
System.out.println("prepare CheesePizza");
}
@Override
void bake() {
System.out.println("bake CheesePizza");
}
@Override
void cut() {
System.out.println("cut CheesePizza");
}
@Override
void box() {
System.out.println("box CheesePizza");
}
}
package staticfactory;
public class ClamPizza extends Pizza {
@Override
void prepare() {
System.out.println("prepare ClamPizza");
}
@Override
void bake() {
System.out.println("bake ClamPizza");
}
@Override
void cut() {
System.out.println("cut ClamPizza");
}
@Override
void box() {
System.out.println("box ClamPizza");
}
}
package staticfactory;
public class VeggiePizza extends Pizza {
@Override
void prepare() {
System.out.println("prepare VeggiePizza");
}
@Override
void bake() {
System.out.println("bake VeggiePizza");
}
@Override
void cut() {
System.out.println("cut VeggiePizza");
}
@Override
void box() {
System.out.println("box VeggiePizza");
}
}
静态工厂(对外提供静态方法进行访问)
package staticfactory;
public class StaticPizzaFactory {
/**
* 负责创建各种类型Pizza的工厂,且为static的!
*/
public static Pizza createPizza(String pizzaName) {
Pizza pizza = null;
if(pizzaName==null || "".equals(pizzaName.trim())) {
throw new RuntimeException("Please specify your pizza!");
}
try {
Class<?> clazz = Class.forName(pizzaName);
pizza = (Pizza) clazz.newInstance();
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException e) {
e.printStackTrace();
throw new RuntimeException(e);
}
return pizza;
}
}
Pizza店
package staticfactory;
public class PizzaStore {
public Pizza orderPizza(String cheeseName) {
Pizza pizza;
pizza = StaticPizzaFactory.createPizza(cheeseName);
pizza.makePizza();
return pizza;
}
}
测试
package test;
import staticfactory.PizzaStore;
public class PizzaTest {
public static void main(String[] args) {
PizzaStore store = new PizzaStore();
orderPizza(store);
}
private static void orderPizza(PizzaStore store) {
store.orderPizza("staticfactory.CheesePizza");
store.orderPizza("staticfactory.ClamPizza");
store.orderPizza("staticfactory.VeggiePizza");
}
}
=======================================================================
简单工厂
组合工厂到类中
package simplefactory;
public class PizzaStore {
//与工厂组合
SimplePizzaFactory factory;
public PizzaStore(SimplePizzaFactory simplePizzaFactory) {
factory = simplePizzaFactory;//实例化工厂
}
public Pizza orderPizza(String cheeseName) {
Pizza pizza;
pizza = factory.createPizza(cheeseName);//委托工厂创建Pizza
pizza.makePizza();
return pizza;
}
}
简单工厂(非静态),需要由对象来调用工厂中的方法
package simplefactory;
public class SimplePizzaFactory {
/**
* 负责创建各种类型Pizza的工厂
*/
public Pizza createPizza(String pizzaName) {
Pizza pizza = null;
if(pizzaName==null || "".equals(pizzaName.trim())) {
throw new RuntimeException("Please specify your pizza!");
}
try {
Class<?> clazz = Class.forName(pizzaName);
pizza = (Pizza) clazz.newInstance();
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException e) {
e.printStackTrace();
throw new RuntimeException(e);
}
return pizza;
}
}
测试
package test;
import simplefactory.SimplePizzaFactory;
import simplefactory.PizzaStore;
public class PizzaTest {
public static void main(String[] args) {
//创建工厂实例对象
SimplePizzaFactory factory = new SimplePizzaFactory();
//将工厂对象传入PizzaStore的构造方法中
PizzaStore store = new PizzaStore(factory);
orderPizza(store);
}
private static void orderPizza(PizzaStore store) {
store.orderPizza("simplefactory.CheesePizza");
store.orderPizza("simplefactory.ClamPizza");
store.orderPizza("simplefactory.VeggiePizza");
}
}
=======================================================================
工厂方法
基类不知道运行时会是哪一个子类在运行---> 解耦,
基类只知道子类可以具备某些行为
具体的对象都是在运行时通过多态实现动态绑定的!
编程时只面对接口,而不是实现类,让代码更具弹性,应对未来的扩展!
简单工厂与工厂方法的区别:
简单工厂,是一个被PizzaStore使用的对象,简单工厂作为外部一个类被组合到PizzaStore中;
简单工厂,把全部的事情在一个地方都处理完了。
工厂方法,有一个抽象方法createPizza(),由PizzaStore的子类自行负责createPizza()的行为;
工厂方法,创建了一个框架(框架依赖工厂方法创建具体类),让子类决定要如何实现。
设计原则
依赖抽象,不要依赖具体类
不能让高层组件依赖于底层组件,而且,不管高层或底层组件,两者都应该依赖于抽象
简单点说,就是要面向抽象编程
变量不可以持有具体类的引用
如果使用new,就会持有具体类的引用。
你可以改用工厂来避开这样的做法。
不要让类派生自具体类
如果派生自具体类,你就依赖具体类。
请派生自一个抽象(接口或抽象类)。
不要覆盖基类中已经实现的方法
如果覆盖基类已经实现的方法,那么你的基类就不是一个真正适合被继承的抽象。
基类中已实现的方法,应该由所有子类共享。
尽量达到上述要求,而不是随时都要遵守,根据实际情况考量!
Pizza 抽象类
package factorymethode;
import java.util.ArrayList;
public abstract class Pizza {
String name;//名称
String dough;//面团
String sauce;//果酱
ArrayList<String> toppings = new ArrayList<String>();//若干佐料
public void prepare(){
System.out.println("firsrt: Prepare " + name);
System.out.println("second: Tossing dough...");
System.out.println("third: Add sauce...");
System.out.println("fouth: Add toppings: ");
for(String topping : toppings) {
System.out.print(" " + topping);
}
System.out.println();
}
public void bake() {
System.out.println("Bake for 25 minutes");
}
public void cut() {
System.out.println("Cutting the pizza into diagonal slices");
}
public void box() {
System.out.println("Place pizza in official PizzaStore box");
}
public String getName() {
return name;
}
}
具体的Pizza-NYStyleCheesePizza
package factorymethode;
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");
}
}
具体的Pizza---ChicagoStyleCheesePizza
package factorymethode;
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");
}
/**
* 覆盖父类的方法
*/
@Override
public void cut() {
System.out.println("Cutting the pizza into square slices");
}
}
PizzaStore抽象类
package factorymethod.pizza;
import factorymethode.Pizza;
public abstract class PizzaStore {
/**
* 订购Pizza的流程是久经考验的,用final修饰,不允许子类进行改变!
*
* 提供了一般的框架(定义好流程),以便创建Pizza
* 依赖抽象工厂方法创建具体的子类,并创建出实际的Pizza
*/
final public Pizza orderPizza(String type) {
//依赖与抽象
Pizza pizza;//超类型/父类/接口
//调用抽象工厂方法,在运行时由具体的子类来返回实例对象
pizza = createPizza(type);
pizza.prepare();
pizza.bake();
pizza.cut();
pizza.box();
return pizza;
}
/**
* 工厂移到这里了,不再单独定义,而是用一个方法(抽象工厂方法)完成对象的创建
* 具体对象由子类根据各自的需求进行返回---解耦
*
* 参数化工厂方法,参数错误将发生运行时异常
* 解决办法:使用枚举类型作为参数,在编译期对参数进行检查
* @return 具体的子类对象
*/
abstract Pizza createPizza(String type);
}
具体的PizzaStore---NYPizzaStore
package factorymethod.pizza;
import factorymethode.NYStyleCheesePizza;
import factorymethode.Pizza;
public class NYPizzaStore extends PizzaStore {
/**
* 子类对抽象方法进行实现
* 返回自己需要的对象
*/
@Override
Pizza createPizza(String type) {
if(type.equals("cheese")) {
return new NYStyleCheesePizza();
}
return null;
}
}
具体的PizzaStore---ChicagoPizzaStore
package factorymethod.pizza;
import factorymethode.ChicagoStyleCheesePizza;
import factorymethode.Pizza;
public class ChicagoPizzaStore extends PizzaStore {
/**
* 子类对抽象方法进行实现
* 返回自己需要的对象
*/
@Override
Pizza createPizza(String type) {
if(type.equals("cheese")) {
return new ChicagoStyleCheesePizza();
}
return null;
}
}
测试
package test;
import factorymethod.pizza.ChicagoPizzaStore;
import factorymethod.pizza.NYPizzaStore;
import factorymethod.pizza.PizzaStore;
import factorymethode.ChicagoStyleCheesePizza;
public class PizzaTest {
public static void main(String[] args) {
orderNYStylePizza();
System.out.println("==========================");
orderChicagoStylePizza();
}
private static void orderChicagoStylePizza() {
PizzaStore store = new ChicagoPizzaStore();
store.orderPizza("cheese");
}
private static void orderNYStylePizza() {
PizzaStore store = new NYPizzaStore();
store.orderPizza("cheese");
}
}
=======================================================================
抽象工厂
提供一个接口(抽象方法),用于创建相关或依赖对象的家族(A1产品,A2产品...)
抽象工厂用来完成一组产品对象的创建
抽象工厂实际内部使用了工厂方法模式
factory1:创建A产品A1,B产品B1
factory2:创建A产品A2,B产品B2
...
上面每一个factory,都是一个工厂方法模式的应用
这些不同的factory,又有自己的基类工厂,abstractFactory
在Client中,只面向abstractFactory,通过abstractFactory进行调用即可。
如此组合起来,就形成了抽象工厂模式
Client(PizzaStore超类)中提供一个抽象方法,这个抽象方法在子类中实现时,将调用上面的abstractFactory进行产品A,B 的创建
基类中组合抽象的基类
在运行时通过多态特性,实现不同子类对象的动态绑定!
工厂方法与抽象工厂的比较
工厂方法:
通过继承父类,实现父类的抽象方法并返回具体的对象
如,NYPizzaStore继承PizzaStore,通过实现createPizza()返回NYStyleCheesePizza
抽象工厂:
通过对象间的组合,通过被组合的对象去调用子类的方法,完成所需对象的创建
如,NYStyleCheesePizza中,通过与PizzaIngredientFactory进行组合,在覆盖父类的抽象方法prepare()时,调用PizzaIngredientFactory对一组原料对象进行创建
可以把一组相关的产品集中起来进行创建;
缺点:如果需要扩展新的产品,就必须改变接口;
抽象工厂模式应用示例
不同地区的PizzaStore需要使用不同的原料来制作Pizza
原料---接口
public interface Cheese {
}
public interface Clam {
}
public interface Dough {
}
public interface Pepperoni {
}
public interface Sauce {
}
public interface Veggies {
}
具体原料---纽约PizzaStore使用的原料,芝加哥PizzaStore使用的原料
public class ChicagoCheese implements Cheese{
}
public class NYCheese implements Cheese{
}
public class ChicagoClam implements Clam{
}
public class NYClam implements Clam{
}
public class ChicagoDough implements Dough{
}
public class NYDough implements Dough{
}
....其它原料类似,不再列出
抽象工厂---定义一组方法对Pizza原料进行创建
package abstractfactory;
import abstractfactory.ingredient.Cheese;
import abstractfactory.ingredient.Clam;
import abstractfactory.ingredient.Dough;
import abstractfactory.ingredient.Pepperoni;
import abstractfactory.ingredient.Sauce;
import abstractfactory.ingredient.Veggies;
/**
* 定义一组产品的创建
*/
public interface PizzaIngredientFactory {
public abstract Dough createDough();
public abstract Sauce createSauce();
public abstract Cheese createCheese();
public abstract Veggies[] createVeggies();
public abstract Pepperoni createPepperoni();
public abstract Clam createClam();
}
具体工厂---NYPizzaIngredientFactory
package abstractfactory;
import abstractfactory.ingredient.Cheese;
import abstractfactory.ingredient.Clam;
import abstractfactory.ingredient.Dough;
import abstractfactory.ingredient.Pepperoni;
import abstractfactory.ingredient.Sauce;
import abstractfactory.ingredient.Veggies;
import abstractfactory.ingredient.impl.NYCheese;
import abstractfactory.ingredient.impl.NYClam;
import abstractfactory.ingredient.impl.NYDough;
import abstractfactory.ingredient.impl.NYPepperoni;
import abstractfactory.ingredient.impl.NYSauce;
import abstractfactory.ingredient.impl.VeggieGarlic;
import abstractfactory.ingredient.impl.VeggieOnion;
/**
* 纽约原料工厂
*
*/
public class NYPizzaIngredientFactory implements PizzaIngredientFactory{
@Override
public Dough createDough() {
return new NYDough();
}
@Override
public Sauce createSauce() {
return new NYSauce();
}
@Override
public Cheese createCheese() {
return new NYCheese();
}
@Override
public Veggies[] createVeggies() {
Veggies[] veggies = {new VeggieGarlic(), new VeggieOnion()};
return veggies;
}
@Override
public Pepperoni createPepperoni() {
return new NYPepperoni();
}
@Override
public Clam createClam() {
return new NYClam();
}
}
具体工厂---ChicagoPizzaIngredientFactory
package abstractfactory;
import abstractfactory.ingredient.Cheese;
import abstractfactory.ingredient.Clam;
import abstractfactory.ingredient.Dough;
import abstractfactory.ingredient.Pepperoni;
import abstractfactory.ingredient.Sauce;
import abstractfactory.ingredient.Veggies;
import abstractfactory.ingredient.impl.ChicagoCheese;
import abstractfactory.ingredient.impl.ChicagoClam;
import abstractfactory.ingredient.impl.ChicagoDough;
import abstractfactory.ingredient.impl.ChicagoPepperoni;
import abstractfactory.ingredient.impl.ChicagoSauce;
import abstractfactory.ingredient.impl.VeggieGarlic;
import abstractfactory.ingredient.impl.VeggieOnion;
/**
* 芝加哥原料工厂
*
*/
public class ChicagoPizzaIngredientFactory implements PizzaIngredientFactory{
@Override
public Dough createDough() {
return new ChicagoDough();
}
@Override
public Sauce createSauce() {
return new ChicagoSauce();
}
@Override
public Cheese createCheese() {
return new ChicagoCheese();
}
@Override
public Veggies[] createVeggies() {
Veggies[] veggies = {new VeggieGarlic(), new VeggieOnion()};
return veggies;
}
@Override
public Pepperoni createPepperoni() {
return new ChicagoPepperoni();
}
@Override
public Clam createClam() {
return new ChicagoClam();
}
}
Pizza类
package abstractfactory.pizza;
import java.util.ArrayList;
import abstractfactory.ingredient.Cheese;
import abstractfactory.ingredient.Clam;
import abstractfactory.ingredient.Dough;
import abstractfactory.ingredient.Pepperoni;
import abstractfactory.ingredient.Sauce;
import abstractfactory.ingredient.Veggies;
public abstract class Pizza {
String name;//名称
/**
* Pizza制作中需要用到的各种原料
*/
Dough dough;//面团
Sauce sauce;//果酱
Veggies veggies;//蔬菜
Cheese cheese;//奶酪
Pepperoni pepperoni;//香肠切片
Clam clam;//蚌
ArrayList<String> toppings = new ArrayList<String>();//若干佐料
/**
* 需要被子类实现的接口(设计模式中,接口的意思:一个抽象方法,一个interface,或一个抽象类)
* 子类在实现时,将利用自己的工厂来创建自己的产品(Dough,Sauce,Veggies,Cheese等的具体类)
*/
public abstract void prepare();
public void bake() {
System.out.println("Bake for 25 minutes");
}
public void cut() {
System.out.println("Cutting the pizza into diagonal slices");
}
public void box() {
System.out.println("Place pizza in official PizzaStore box");
}
public void setName(String name) {
this.name = name;
}
public String getName() {
return name;
}
}
具体的Pizza---NYStyleCheesePizza
package abstractfactory.pizza;
import abstractfactory.PizzaIngredientFactory;
/**
* 通过抽象工厂完成对一组原料的实例化
*
*/
public class NYStyleCheesePizza extends Pizza {
//与原料工厂进行组合
PizzaIngredientFactory ingredientFactory;//---抽象工厂模式
public NYStyleCheesePizza(PizzaIngredientFactory ingredientFactory) {
this.ingredientFactory = ingredientFactory;
}
/**
* 运行时将由传入的具体原料工厂完成对应原料的创建
*/
@Override
public void prepare() {
System.out.println("Preparing "+name);
//通过原料工厂,对从父类继承下来的那些属性进行初始化
dough = ingredientFactory.createDough();
sauce = ingredientFactory.createSauce();
cheese = ingredientFactory.createCheese();
}
}
具体的Pizza---ChicagoStyleCheesePizza
package abstractfactory.pizza;
import abstractfactory.PizzaIngredientFactory;
/**
* 通过抽象工厂完成对一组原料的实例化
*
*/
public class ChicagoStyleCheesePizza extends Pizza {
//与原料工厂进行组合
PizzaIngredientFactory ingredientFactory;//---抽象工厂模式
public ChicagoStyleCheesePizza(PizzaIngredientFactory ingredientFactory) {
this.ingredientFactory = ingredientFactory;
}
/**
* 覆盖父类的方法
*/
@Override
public void cut() {
System.out.println("Cutting the pizza into square slices");
}
/**
* 运行时将由传入的具体原料工厂完成对应原料的创建
*/
@Override
public void prepare() {
System.out.println("Preparing "+name);
//通过原料工厂,对从父类继承下来的那些属性进行初始化
dough = ingredientFactory.createDough();
sauce = ingredientFactory.createSauce();
cheese = ingredientFactory.createCheese();
clam = ingredientFactory.createClam();
}
}
PizzaStore
package abstractfactory.store;
import abstractfactory.pizza.Pizza;
public abstract class PizzaStore {
/**
* 订购Pizza的流程是久经考验的,用final修饰,不允许子类进行改变!
*
* 提供了一般的框架(定义好流程),以便创建Pizza
* 依赖抽象工厂方法创建具体的子类,并创建出实际的Pizza
*/
final public Pizza orderPizza(String type) {
//依赖与抽象
Pizza pizza;//超类型/父类/接口
//调用抽象工厂方法,在运行时由具体的子类来返回实例对象
pizza = createPizza(type);
pizza.prepare();
pizza.bake();
pizza.cut();
pizza.box();
return pizza;
}
/**
* 工厂移到这里了,不再单独定义,而是用一个方法(抽象工厂方法)完成对象的创建
* 具体对象由子类根据各自的需求进行返回---解耦
*
* 参数化工厂方法,参数错误将发生运行时异常
* 解决办法:使用枚举类型作为参数,在编译期对参数进行检查
* @return 具体的子类对象
*/
abstract Pizza createPizza(String type);//---工厂方法模式
}
具体的PizzaStore----NYPizzaStore
package abstractfactory.store;
import abstractfactory.NYPizzaIngredientFactory;
import abstractfactory.PizzaIngredientFactory;
import abstractfactory.pizza.NYStyleCheesePizza;
import abstractfactory.pizza.Pizza;
public class NYPizzaStore extends PizzaStore {
/**
* 子类对抽象方法进行实现---工厂方法模式
* 返回自己需要的对象
*/
@Override
Pizza createPizza(String type) {
Pizza pizza = null;
//引入New York的原料工厂
//工厂在方法中被指定,外部并不需要知道
PizzaIngredientFactory ingredientFactory = new NYPizzaIngredientFactory();
if(type.equals("cheese")) {
pizza = new NYStyleCheesePizza(ingredientFactory);
pizza.setName("New York Style Cheese Pizza from abstract factory!");
return pizza;
}
return null;
}
}
具体的PizzaStore----ChicagoPizzaStore
package abstractfactory.store;
import abstractfactory.ChicagoPizzaIngredientFactory;
import abstractfactory.PizzaIngredientFactory;
import abstractfactory.pizza.ChicagoStyleCheesePizza;
import abstractfactory.pizza.Pizza;
public class ChicagoPizzaStore extends PizzaStore {
/**
* 子类对抽象方法进行实现---工厂方法模式
* 返回自己需要的对象
*/
@Override
Pizza createPizza(String type) {
Pizza pizza = null;
//引入Chicago的原料工厂
//工厂在方法中被指定,外部并不需要知道
PizzaIngredientFactory ingredientFactory = new ChicagoPizzaIngredientFactory();
if(type.equals("cheese")) {
pizza = new ChicagoStyleCheesePizza(ingredientFactory);
pizza.setName("Chicago Style Cheese Pizza from abstract factory!");
return pizza;
}
return null;
}
}
测试
package test;
import abstractfactory.store.ChicagoPizzaStore;
import abstractfactory.store.NYPizzaStore;
import abstractfactory.store.PizzaStore;
public class PizzaTest {
public static void main(String[] args) {
orderNYStylePizza();
System.out.println("==========================");
orderChicagoStylePizza();
}
private static void orderChicagoStylePizza() {
PizzaStore store = new ChicagoPizzaStore();
store.orderPizza("cheese");
}
private static void orderNYStylePizza() {
PizzaStore store = new NYPizzaStore();
store.orderPizza("cheese");
}
}