想多了都是问题,想通了都是答案
第一部分,简单工厂模式
哪朵玫瑰没有荆棘,最好的报复是美丽,最美的盛开是反击,别让谁去改变了你。
当看到new,就会想到具体
先看一段代码
Duck duck;
if (picnic) {
duck = new MallardDuck();
} else if (hunting) {
duck = new DecoyDuck();
} else if (inBathTub) {
duck = new RubberDuck();
}
究竟要实例化哪个类,要在运行时由一些条件来决定。当看到这样的代码,一旦有变化或扩展,就必须重新打开这段代码进行检查和修改,维护与更新困难,也更容易犯错。
识别变化的方面
你有一家披萨店,你的代码可能这么写:
Pizza orderPizza() {
Pizza pizza = new Pizza();
pizza.prepare();
pizza.bake();
pizza.cut();
pizza.box();
return pizza;
}
现在,你需要更多的披萨类型:
Pizza orderPizza(String type) {
Pizza pizza;
// 根据不同的类型,创建不同的披萨
if (type.equals("cheese")) {
pizza = new CheesePizza();
} else if (type.equals("greek")) {
pizza = new GreekPizza();
} else if (type.equals("pepperoni")) {
pizza = new PepperoniPizza();
}
pizza.prepare();
pizza.bake();
pizza.cut();
pizza.box();
return pizza;
}
但是现在其它的披萨店推出了更多口味更加流行的披萨口味,你为了不被淘汰,也要更新店铺的披萨口味同时把其中不受欢迎的披萨进行淘汰。很明显,上面中间那段代码就要根据情况不停地进行修改,违反了代码的设计原则,对扩展开发,对修改关闭。
封装创建对象的代码
根据代码的设计原则,把其中易于改变的地方提出来单独进行封装。
Pizza orderPizza(String type) {
Pizza pizza;
// 这易于变化的部分,提处理单独封装
pizza.prepare();
pizza.bake();
pizza.cut();
pizza.box();
return pizza;
}
建立一个简单工厂
public class SimplePizzaFactory {
public Pizza createPizza(String type) {
Pizza pizza = null;
// 根据不同的类型,创建不同的披萨
if (type.equals("cheese")) {
pizza = new CheesePizza();
} else if (type.equals("greek")) {
pizza = new GreekPizza();
} else if (type.equals("pepperoni")) {
pizza = new PepperoniPizza();
}
retirn pizza;
}
}
把这个提出来处理的对象称为“工厂”,现在orderPizza()
就成了这个简单工厂的客户,当需要生产披萨时,就叫工厂生产一个。
这么做有什么好处?似乎只是把问题搬到了另一个对象罢了,问题依然存在。
不,最直观的一个方面就是SimplePizzaFactory
可以不单单为orderPizza
服务了,他可以有许多个客户。比如
有一个外卖服务类HmoeDelivery
,会对工厂生成的披萨进行不同的处理,即修改下面这段代码
pizza.prepare();
pizza.bake();
pizza.cut();
pizza.box();
换成其他的处理方式。所以,把创建披萨的代码包装起来,当以后实现改变时,只需要修改这个类即可,其它的客户类不用动。
重做pizzaStore类,定义简单工厂
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;
}
}
要知道,其实上面这种设计模式,并不是传统意义上的工厂模式,而是一种好的编程习惯。
第二部分,工厂方法模式
加盟披萨店
现在你的披萨店经营有成,击败了其它的竞争者,大家都希望披萨店能够在自家门口有加盟店。
但是,由于地域之间的差别,每一家加盟店都可能要提供不同风味的披萨(比如纽约、芝加哥、加州)。
第一个做法,就是创建几个不同的工厂
NYPizzaFactory nyFactory = new NYPizzaFactory();
PizzaStore nyStore = new PizzaStore(nyFactory);
nyStore.orderPizza("Veggie");
根据上面的方法,各个区域的加盟店确实使用的是你的工厂生产的披萨饼。但是,对于披萨的制作流程确实没有按照总公司的制作流程
pizza.prepare();
pizza.bake();
pizza.cut();
pizza.box();
这些加盟店不按照规定的流程走,使得做出来的披萨非常难吃,这大大影响了披萨店的口碑。所以,你想要有一套框架,在各个区域加盟店能生产符合地域口味的披萨,同时又能严格按照总公司的披萨制作流程,保证披萨的质量。
给披萨店制定框架
既能根据地域生产不同口味披萨,同时严格执行披萨制作流程
定义总公司披萨店抽象类,其它店铺继承这个类
public abstract class PizzaStore {
Pizza orderPizza(String type) {
Pizza pizza;
pizza = createPizza(type);
pizza.prepare();
pizza.bake();
pizza.cut();
pizza.box();
return pizza;
}
// 把制作不同口味的披萨放到子类加盟店中做决定
abstract Pizza createPizza(String type)
}
开一家纽约披萨加盟店
public class NYPizzaStore extends PizzaStore {
Pizza createPizza(String type) {
Pizza pizza = null;
// 根据不同的类型,创建不同的披萨
if (type.equals("cheese")) {
pizza = new CheesePizza();
} else if (type.equals("greek")) {
pizza = new GreekPizza();
} else if (type.equals("pepperoni")) {
pizza = new PepperoniPizza();
}
return pizza;
}
}
工厂方法用来处理对象的创建,并将这样的行为封装在子类中,实际生产什么口味的披萨由子类来决定。
public static void main(String[] args) {
NYPizzaStore nyStore = new NYPizzaStore();
ChicagoPizzaStore chicagoStore = new ChicagoPizzaStore();
Pizza pizza = nyStore.orderPizza("cheese");
Pizza pizza = chicagoStore.orderPizza("cheese");
}
这样既能根据地域生产不同口味披萨,同时严格执行披萨制作流程。
认识与定义工厂方法模式
所有工厂模式都是用来封装对象的创建。工厂方法模式(Factory Method Pattern)通过让子类决定该创建的对象是什么,来达到将对象创建的过程封装的目的。
创建者(Creator)类
抽象创建者类,定义了一个抽象的工厂方法,让子类实现此方法制造产品。
产品类
这是具体的产品,所有店里能实际制造的披萨在这里实现。
根据上面披萨店一系列的演变,很清楚地可以看出,在代码里减少对于具体类的依赖是件好事。事实上,有一个OO设计原则就正式阐明了这一点,即依赖倒置原则。
设计原则:
要依赖抽象,不要依赖具体。
不能让高层组件依赖底层组件,而且,不管高层或底层组件,两者都应该依赖抽象。
使用工厂方法之后,高层组件和底层组件都依赖了Pizza抽象。
第三部分,抽象工厂模式
再回到披萨店
现在披萨店的设计变得很棒,具有弹性的框架,而且遵循设计原则。现在加盟店都遵循你制定的设计流程,但是有一些加盟店,使用低价的原料来增加利润。你必须采取一些手段,以免长此以往毁了自己披萨店的招牌。
你打算确保每一家加盟店使用高质量的原料,因此打算建造一家生产原料的工厂,并将原料运送到各家加盟店。
但是每一个地区制作披萨用到的原料不一样。
所以,你打算根据地区不同,建立不同的原料家族。
建造原料工厂
现在建造一个原料工厂来生产原料,这个工厂将负责创建原料家族中的每一种原料。即这个工厂需要生产面团、酱料、芝士。
public class PizzaIngredientFactory {
public Dough createDough();
public Sauce createSauce();
public Cheese createCheese();
public Veggies[] createVeggies();
public Pepperoni createPepperoni();
public Clams createClam();
}
创建纽约原料工厂
public class NYPizzaIngredientFactory implemes PizzaIngredientFactory {
public Dough createDough() {
return new ThinCrustDough();
}
public Sauce createSauce() {
return new MarinaraSauce();
}
public Cheese createCheese() {
return new ReggianoCheese();
}
public Veggies[] createVeggies() {
Veggies vegggies[] = {new Garlic(), new Onion(), new Mushroom(), new RedPepper()}
return veggies;
}
public Pepperoni createPepperoni() {
return new SlicedPepperoni();
}
public Clams createClam() {
return new FreshClams();
}
}
现在,我们不需要设计两个不同的类来处理不同风味的披萨了,直接让原料工厂处理这种地域差异就可以了。
蛤蜊披萨实现
public class ClamPizza extends Pizza {
PizzaIngredientFactory ingredientFactory;
public ClamPizza(PizzaIngredientFactory ingredientFactory) {
this.ingredientFactory = ingredientFactory;
}
void prepare() {
System.out.println("Preparing " + name);
dough = ingredientFactory.createDough();
sauce = ingredientFactory.createSauce();
cheese = ingredientFactory.createCheese();
clam = ingredientFactory.createClam();
}
}
纽约披萨加盟店
public class NYPizzaStore extends PizzaStore {
protected Pizza createPizza(String type) {
Pizza pizza = null;
PizzaIngredientFactory ingredientFactory = new NYPizzaIngredientFactory();
// 根据不同的类型,创建不同的披萨
if (type.equals("cheese")) {
pizza = new CheesePizza(ingredientFactory);
pizza.setName("New York Style Cheese Pizza")
} else if (type.equals("greek")) {
pizza = new GreekPizza(ingredientFactory);
pizza.setName("New York Style greek Pizza")
} else if (type.equals("pepperoni")) {
pizza = new PepperoniPizza(ingredientFactory);
pizza.setName("New York Style pepperoni Pizza")
}
return pizza;
}
}
定义抽象工厂模式
抽象工厂模式
提供一个接口,用于创建相关或依赖对象的家族,而不需要明确指定具体类。
即抽象工厂允许客户使用抽象的接口来创建一组相关的产品,而不需要知道或关心实际产出的具体产品是什么。
标签:披萨,模式,工厂,new,Pizza,type,public,pizza From: https://www.cnblogs.com/l12138h/p/16983564.html