1、抽象工厂
1)定义:提供了一个接口,用于创建相关或依赖对象的家族,而不需要明确指定具体类
2)抽象工厂允许客户使用抽象的接口来创建一组相关的产品,而不需要知道实际产出的具体产品是什么,这样一来,客户就从具有的产品中被解耦
3)以客户定制披萨为例:
a)创建披萨店
b)点餐,点某种披萨
c)厨房开始做:准备材料、烘烤、切片、装盒,除了材料不同,其他的制作步骤都相同,所以完全可以将做披萨抽出到一个抽象类中,子类去实例化
4)实例代码
抽象店铺:PizzaStore.java
public abstract class PizzaStore {
public Pizza orderPizza(String type){
Pizza pizza;
pizza = createPizza(type);
pizza.prepare();
pizza.bake();
pizza.cut();
pizza.box();
return pizza;
}
//抽象类方法,由子类取实例化,本末倒置
protected abstract Pizza createPizza(String type);
}
具体店铺子类(纽约店铺),用于重新创建符合纽约风味的某种披萨(生的披萨): NYPizzaStore.java
/**
* 纽约披萨厂
*/
public class NYPizzaStore extends PizzaStore{
@Override
protected Pizza createPizza(String type) {
Pizza pizza = null;
PizzaIngredientFactory pizzaIngredientFactory = new NYPizzaIngredientFactory();
switch (type){
case "cheese":
pizza = new CheesePizza(pizzaIngredientFactory);
pizza.setName("New York Style Cheese Pizza");
break;
case "veggie":
pizza = new VeggiePizza(pizzaIngredientFactory);
pizza.setName("New York Style veggie Pizza");
break;
case "clam":
pizza = new ClamPizza(pizzaIngredientFactory);
pizza.setName("New York Style clam Pizza");
break;
case "pepperoni":
pizza = new PepperoniPizza(pizzaIngredientFactory);
pizza.setName("New York Style pepperoni Pizza");
break;
}
return pizza;
}
}
奶酪披萨、哈利披萨等种类披萨有统一的接口工厂,用于配置各种原料 PizzaIngredientFactory.java
/**
*接口用于生产原料
*/
public interface PizzaIngredientFactory {
Dough createDough();
Sauce createSauce();
Cheese createCheese();
Veggies createVegies();
Pepperoni createPepperoni();
Clams createClam();
}
纽约店铺披萨的材料工厂,用于生产符合纽约风味的原料:NYPizzaIngredientFactory.java
/**
* 纽约披萨工厂
*/
public class NYPizzaIngredientFactory implements PizzaIngredientFactory {
@Override
public Dough createDough() {
Dough dough = new Dough();
dough.setName("我是面团");
return dough;
}
@Override
public Sauce createSauce() {
Sauce sauce = new Sauce();
sauce.setName("我是酱紫");
return sauce;
}
@Override
public Cheese createCheese() {
Cheese cheese = new Cheese();
cheese.setName("我是新鲜的奶酪");
return cheese;
}
@Override
public Veggies createVegies() {
Veggies veggies = new Veggies();
veggies.setName("我是新鲜的蔬菜");
return veggies;
}
@Override
public Pepperoni createPepperoni() {
Pepperoni p = new Pepperoni();
p.setName("好吃的香肠");
return p;
}
@Override
public Clams createClam() {
Clams clams = new Clams();
clams.setName("我是活着的哈利");
return clams;
}
}
披萨本身是个抽象类,定义了所有种类披萨需要的原料以及制作程序Pizza.java
/**
* @author one3c-zanpengfei 抽象类-统一父类
*/
public abstract class Pizza {
String name;
Dough dough; //面团
Sauce sauce;// 酱紫
Veggies veggies[];//蔬菜
Cheese cheese;//奶酪
Pepperoni pepperoni;//意大利香肠
Clams clams; //哈利
abstract void prepare();
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 officeal PizzaStore box");
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
有了原料工厂,可以生产某种披萨原料:奶酪披萨的原料生产CheesePizza.java,继承与父类披萨,具体来实例化父类
/**
* 奶酪披萨
*/
public class CheesePizza extends Pizza {
PizzaIngredientFactory ingredientFactory;
public CheesePizza(PizzaIngredientFactory ingredientFactory) {
this.ingredientFactory = ingredientFactory;
}
//当需要原料时和工程要
@Override
void prepare() {
System.out.println("Prepareing " + name);
dough = ingredientFactory.createDough();
sauce = ingredientFactory.createSauce();
cheese = ingredientFactory.createCheese();
}
}
测试类
public class Customer {
//模拟店里的某个顾客,点餐过程
public static void main(String[] args) {
//1 创建一个NYPizzaStore披萨店实例
PizzaStore nyPizzaStore = new NYPizzaStore();
Pizza pizza = nyPizzaStore.orderPizza("cheese");
System.out.println(pizza);
}
}
5)总结:
a)抽象工厂使用对象组合:对象的创建被实现在工厂接口所暴露出来的方法中,例如生成原料
b)抽象工厂创建相关的对象家族,而不需要依赖他们的具体类
2、工厂
1)定义:定义了一个创建对象的接口,但由自来决定要实例化类的哪一个,工厂方法让类把实例化推迟到了子类
2)实例代码
顶层抽象披萨店,相当于总店,具体的创建由分店即子类去完成PizzaStore.java,定义了披萨的制作过程,其中披萨本身的属性与抽象工程一致
/**
* 生产披萨工程,流水线工作
*/
public abstract class PizzaStore {
public Pizza orderPizza(String type){
Pizza pizza;
pizza = createPizza(type);
pizza.prepare();
pizza.bake();
pizza.cut();
pizza.box();
return pizza;
}
//抽象类方法,由子类取实例化,本末倒置
protected abstract Pizza createPizza(String type);
}
创建纽约的披萨分店: NYPizzaStore.java
/**
* 根据披萨类型不同,生产不同的种类的纽约披萨
*/
public class NYPizzaStore extends PizzaStore {
@Override
protected Pizza createPizza(String type) {
switch (type){
case "cheese":
return new NYStyleCheesePizza();
case "veggie":
return new NYStyleCheesePizza();
case "clam":
return new NYStyleCheesePizza();
case "pepperoni":
return new NYStyleCheesePizza();
}
return null;
}
}
测试类
/**
* 客户点餐
*/
public class Customer {
public static void main(String[] args) {
PizzaStore store = new NYPizzaStore();
Pizza pizza = store.orderPizza("cheese");
System.out.println("Ethan ordered a " + pizza.getName());
}
}
3)解释:
a)顾客开始点餐,调用该店铺的order方法:其实是调用父类店铺的订餐方法
b)店铺开始制作:准备原材料、烘烤、切片等方法
4)设计模式原则:依赖倒置原则:要依赖抽象,不要依赖具体类,也就是说不能让高层组件依赖底层组件,而且不管高层或底层组件,“俩者”都应该依赖于抽象
5)总结:
a)工厂方法使用继承,把对象的创建委托给子类,子类事项工厂方法来创建对象
b)所有的工厂模式都通过减少应用程序和具体类之间的依赖促进松耦合
c)工厂方法允许类将实例化延迟到子类进行
d)工厂方法建议我们针对抽象编程,而不是针对具体类编程
3、工厂方法与抽象工厂区别
1)俩者都是负责创建对象,但是工厂方法是通过继承,而抽象工厂通过对象的组合
2)抽象工厂提供一个用来创建一个产品家族的抽象类型,这个类型的子类定义了产品别产生的方法,要想使用这个工厂,必须先实例化它,然后将他传入到一些针对抽象类型所写的代码中,所以和工厂方法一样,可以把客户从所使用的实际具体产品中解耦,可以把一群相关的产品集合起来
3)抽象工厂用在当需要创建产品家族和想让创建的相关产品集合起来时,可以考虑用抽象工厂
4)工厂方法可以把客户代码从需要实例化的具体类中解耦