工厂模式
注意:接口:泛指狭义上的接口,也可以指抽象类
概念解释
- 工厂方法模式:
定义一个创建对象的接口,但由子类决定实例化的具体类型。即,将类的实例化推迟到了子类。 - 抽象工厂模式
提供一个接口,用于创建相关或依赖对象的家族。也是吧类的实例推迟到了子类
具体区别下文会有介绍。
- 简单工厂的方式 不是设计模式,更多的是一种编码规范。
需求1
创建一个不同地区(纽约、芝加哥)风味的披萨点 生产的不同种类( chessse veggie)披萨
1 普通实现
// 披萨店直接做具体类型的披萨 耦合性极大
public class DependentPizzaStore {
public Pizza createPizza(String style, String type) {
Pizza pizza = null;
if (style.equals("NY")) {
if (type.equals("cheese")) {
pizza = new NYStyleCheesePizza();
} else if (type.equals("veggie")) {
pizza = new NYStyleVeggiePizza();
}
} else if (style.equals("Chicago")) {
if (type.equals("cheese")) {
pizza = new ChicagoStyleCheesePizza();
} else if (type.equals("veggie")) {
pizza = new ChicagoStyleVeggiePizza();
}
} else {
System.out.println("Error: invalid type of pizza");
return null;
}
pizza.prepare();
pizza.bake();
pizza.cut();
pizza.box();
return pizza;
}
}
2 简单工厂产生具体披萨 披萨店调用工厂做出具体披萨
简单工厂其实不是一个设计模式,更像是一种变成习惯
// 普通做法相比 只是将做披萨封装出去,有工厂提供。
public class SimplePizzaFactory {
public Pizza createPizza(String type) {// type 类型 即代表披萨店区域,又代表披萨的种类。两个维度 这样不好
Pizza pizza = null;
if (type.equals("NYcheese")) {
pizza = new NYCheesePizza();
} else if (type.equals("NYveggie")) {
pizza = new NYVeggiePizza();
}else if (type.equals("Chicagocheese")) {
pizza = new ChicagoCheesePizza();
} else if (type.equals("Chicagoveggie")) {
pizza = new ChicagoVeggiePizza();
}
return pizza;
}
}
public class PizzaStore {
SimplePizzaFactory factory;
public PizzaStore(SimplePizzaFactory factory) {
this.factory = factory;
}
public Pizza orderPizza(String type) {
Pizza pizza = factory.createPizza(type);
pizza.prepare();
pizza.bake();
pizza.cut();
pizza.box();
return pizza;
}
}
3 工厂方法模式
// 把做什么风味的决定权交给披萨店(PizzaStore) 把做披萨还得限制于具体PizzaStore类中
public abstract class PizzaStore {
public Pizza orderPizza(String type) {
Pizza pizza = createPizza(type);
System.out.println("--- Making a " + pizza.getName() + " ---");
pizza.prepare();
pizza.bake();
pizza.cut();
pizza.box();
return pizza;
}
// 由子披萨店,即各地区披萨店自主决定(pizzaStore的类型)披萨风味和披萨种类(type)
abstract Pizza createPizza(String type);
}
public class NYPizzaStore extends PizzaStore {
Pizza createPizza(String item) {
// 另外,靠字符串匹配,出错几率大些,可用代表参数类型的对象,静态变量、枚举代替
if (item.equals("cheese")) {
return new NYStyleCheesePizza();
} else if (item.equals("veggie")) {
return new NYStyleVeggiePizza();
} else return null;
}
}
public class ChicagoPizzaStore extends PizzaStore {
Pizza createPizza(String item) {
if (item.equals("cheese")) {
return new ChicagoStyleCheesePizza();
} else if (item.equals("veggie")) {
return new ChicagoStyleVeggiePizza();
} else return null;
}
}
// 测试
public class PizzaTestDrive {
public static void main(String[] args) {
PizzaStore nyStore = new NYPizzaStore();
PizzaStore chicagoStore = new ChicagoPizzaStore();
Pizza pizza = nyStore.orderPizza("cheese");
System.out.println("Ethan ordered a " + pizza.getName() + "\n");
pizza = chicagoStore.orderPizza("cheese");
System.out.println("Joel ordered a " + pizza.getName() + "\n");
pizza = nyStore.orderPizza("veggie");
System.out.println("Ethan ordered a " + pizza.getName() + "\n");
pizza = chicagoStore.orderPizza("veggie");
System.out.println("Joel ordered a " + pizza.getName() + "\n");
}
}
// 公共代码
public abstract class Pizza {
//原料 下边会有对原料的变体
String name;
String dough;
String sauce;
String veggie;
String clam;
String perpersoni;
ArrayList<String> toppings = new ArrayList<String>();
void prepare() {// 对基本披萨的处理
System.out.println("Prepare " + name);
System.out.println("Tossing dough...");
System.out.println("Adding sauce...");
System.out.println("Adding toppings: ");
for (String topping : toppings) {
System.out.println(" " + topping);
}
}
void bake() {
System.out.println("Bake for 25 minutes at 350");
}
void cut() {
System.out.println("Cut the pizza into diagonal slices");
}
void box() {
System.out.println("Place pizza in official PizzaStore box");
}
public String getName() {
return name;
}
public String toString() {
StringBuffer display = new StringBuffer();
display.append("---- " + name + " ----\n");
display.append(dough + "\n");
display.append(sauce + "\n");
for (String topping : toppings) {
display.append(topping + "\n");
}
return display.toString();
}
}
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");
}
}
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");
}
}
简单工厂与工厂方法的区别
简单工厂把全部工作在一个地方都处理完了;它把创建产品的代码封装起来,但不具备工厂方法的弹性,因为简单工厂不能变更正在创建的产品
抽象工厂方法却是创建一个框架,让子类决定如何实现,即子类决定产品类型
需求2 保证风味种类或者说原料都得是指定的
用对象来限定种类
4 抽象工厂模式
//定义产生产品家族的接口-抽象工厂
public interface PizzaIngredientFactory {
//每种原料就是一种类
public Dough createDough();
public Sause createSause();
public Cheese createCheese ();
}
// 具体工厂决定具体的产品
public NYPizzaIngredientFactory implements PizzaIngredientFactory {
public Dough createDough(){
return ThinCrustDoough();
}
public Sause createSause(){
return MarinaraSause();
}
}
// 给披萨加上配料
public abstract class Pizza{
public Dough dough;
public Sause sause;
public Veggies veggies[];
public Cheese cheese;
public Peppersoni perppersoni;
public Clams clams;
abstract void prepare();// 声明称抽象,从原料工厂中获取pizza所需的具体风味原料
void bake() {
System.out.println("Bake for 25 minutes at 350");
}
void cut() {
System.out.println("Cut the pizza into diagonal slices");
}
void box() {
System.out.println("Place pizza in official PizzaStore box");
}
public String getName() {
return name;
}
public String toString() {
StringBuffer display = new StringBuffer();
display.append("---- " + name + " ----\n");
display.append(dough + "\n");
display.append(sauce + "\n");
for (String topping : toppings) {
display.append(topping + "\n");
}
return display.toString();
}
}
//具体类型的披萨
public ChessPizza extends Pizza{
PizzaIngredientFactory pizzaIngredientFactory; // 盛放具体类型的原料工厂
public ChessPizza(PizzaIngredientFactory pizzaIngredientFactory){
this.pizzaIngredientFactory = pizzaIngredientFactory;
}
@Override
public void prepare(){
this.dough = pizzaIngredientFactory.getDough();
this.sause= pizzaIngredientFactory.getSause();
}
}
public Veggiesizza extends Pizza{
PizzaIngredientFactory pizzaIngredientFactory; // 盛放具体类型的原料工厂
public ChessPizza(PizzaIngredientFactory pizzaIngredientFactory){
this.pizzaIngredientFactory = pizzaIngredientFactory;
}
@Override
public void prepare(){// 具体风味的不同,及配料的不同
this.dough = pizzaIngredientFactory.getDough();
this.sause= pizzaIngredientFactory.getSause();
this.veggies= pizzaIngredientFactory.getVeggies();
}
}
//纽约地区的披萨店
public NYPizzaStore extends PizzaStore {
Pizza pizza = null;
PizzaIngredientFactory pizzaIngredientFactory = new NYPizzaIngredientFactory();//NYPizzaIngredientFactory是NYPizzaStore披萨店的配料
@Override
public Pizza createPizza(String type){
if("cheese".equals(type)){
pizza = new CheesePizza(pizzaIngredientFactory);
}
if("veggie".equals(type)){
pizza = new Veggiesizza(pizzaIngredientFactory);
}
}
}
//测试
public orderPizzaTest{
main(String[] args){
//由子类决定store 以及风味(配料)的类型
PizzaStore nyStore = new NYPizzaStore();
PizzaIngredientFactory nyPizzaIngredientFactory = new NYPizzaIngredientFactory();
Pizza chessPizza = nyStore.orderPizza("cheese"); //完成了下边的工作
- //一旦确定了PizzaStore的类型,也就确定了原料工厂类型;设置"cheese"类型时,把原料工厂类型设置给了chessPizza;
- // Pizza chessPizza = createPissa("cheese"); 完成了基本的创建
- // chessPizza = chessPizza.prepare()//pizza的具体类型调用后续处理,将原料设置给了基本的披萨
}
}
工厂方法和抽象工厂的区别
类/对象
工厂方法使用的是类, 去继承一个类,并覆盖它的工厂方法;
抽象工厂使用的是对象, 去组合。实例化一个产品/一群产品
这也说明了两者的使用场景;
抽象方法模式中的方法其实就是工厂模式实现的
脑袋有点蒙了 ,有时间再做更正