一、简单工厂
举个栗子:
开个披萨店:
Pizza orderPizza() {
Pizza pizza = new Pizza(); //创建个pizza
pizza.prepare(); //备料
pizza.bake(); //烘烤
pizza.cut(); //切片
pizza.box(); //装盒
}
披萨店不能只有一种披萨,要做各种类型的披萨怎么办呢?
Pizza orderPizza(String type) {//要做什么pizza就传入pizza的种类
Pizza pizza;
if (type.equals(“cheese”)) { //根据pizza的类型,来实例化正确的具体类
pizza = new CheesePizza();
} else if ...
pizza.prepare(); //备料
pizza.bake(); //烘烤
pizza.cut(); //切片
pizza.box(); //装盒
}
披萨店扩张了,制作的披萨种类更多了,有些披萨卖得不好,不做了,这怎么做呢?
只能在上面代码里删掉一些if else,再添加上一些if else。在上面这段代码中,if else这段会随着需求的变化而变化,但对披萨的备料,烘烤等操作是不会变化的。
Tips:
开闭原则:
扩展开放,对修改关闭。一个软件实体应该通过扩展来实现变化,而不是通过修改已有代码来实现变化。
很明显,上面的这种设计,违背了开闭原则,这就到了使用封装的时候了。把会经常修改的if else这段代码抽离到另一个对象中,这个对象只负责创建披萨。
这个新对象SimplePizzaFactory就称为“工厂”,专门用来生产不同种类的披萨,orderPizza()就是这个对象的客户,当需要披萨时,就叫披萨工厂做一个,至于怎么做,就不用关心了。
卖披萨分三步:
1.建个披萨工厂专门做披萨
public class SimplePizzaFactory { //只负责创建披萨
public Pizza createPizza(String type) { //这个方法为所有用户实例化新对象
Pizza pizza = null;
if (type.equals(“cheese”)) { //之前的if else
pizza = new CheesePizza();
} else if ...
return pizza;
}
}
2.建个披萨店
public class PizzaStore {
SimplePizzaFactory factory; //为披萨店PizzaStore加上对SimplePizzaFactory的引用
public PizzaStore (SimplePizzaFactory factory) { //披萨店PizzaStore的构造器,以一个工厂做参数
This.factory = factory;
}
public Pizza orderPizza (String type) {
Pizza pizza;
pizza = factory.createPizza(type);//通过传入类型来使用工厂加工披萨
pizza.prepare(); //备料
pizza.bake(); //烘烤
...
return pizza;
}
}
3.披萨卖起来了
pubic class PizzaTest {
public static void main (String[] args) {
SimplePizzaFactory factory = new SimplePizzaFactory();//创建一个披萨工厂
PizzaStore story = new PizzaStore(factory); //建立一个披萨店,从披萨工厂里获取披萨
store.orderPizza(“Cheese”);//选择披萨的具体口味
}
}
简单工厂其实不是一个设计模式,反而比较像一种编程习惯,把变化的部分单独封装起来。
二、工厂模式
披萨店有了加盟店啦~~但是每个加盟店想提供适合自己所在区域口味的披萨,所以加盟店需要有一个适合自己的工厂。
还是卖披萨的那三步:
1.建一个专门生产纽约风味的披萨工厂
abstract class PizzaFactory {
public abstract Pizza createPizza();
}
public class NYPizzaFactory extent PizzaFactory {//继承抽象工厂类,创建具体的实例方法
public Pizza createPizza(String type) {
... //个性化定制纽约口味披萨
return pizza;
}
}
2.开个加盟店
到这里发现,加盟店也需要个性化定制啊,不能通用就是PizzaStore,也得有什么NYPizzaStore啊,那就把披萨店也抽象出来。
public abstract class PizzaStore { //创建一个抽象的披萨店PizzaStore类
public Pizza orderPizza(String type) {//处理披萨订单
Pizza pizza;
pizza = createPizza(type);//调用的就是下方的createPizza方法,这个方法由各个加盟店自己定义,也就是说每个PizzaStore的子类都会覆盖createPizza()方法
//pizza的后续制作不变,加盟店无法影响他们,加盟店只负责确定口味,在外部调用orderPizza,而orderPizza里的createPizza是加盟店自己定义的具体制作什么口味的披萨
pizza.prepare(); //备料
pizza.bake(); //烘烤
...
return pizza;
}
protected abstract Pizza createPizza(String type);//由各个加盟店自己决定如何做披萨
}
现在就开个加盟店
public class NYPizzaStore extends PizzaStore {
Pizza createPizza(String item) { //必须实现createPizza()方法,因为在PizzaStore里他是抽象的
if (item.equals(“cheese”)) { //具体的披萨口味
return new NYStyleCheesePizza();
} else if ...
}
}
3.卖个纽约风味的芝士披萨
public class PizzaTest {
public Static void main(String[] args) {
PizzaStroe nyStore = new NYPizzaStore();//建个纽约加盟店
Pizza pizza = nyStore.orderPizza(“cheese”);//定个cheese披萨
}
}
Tips:
重点解释abstract Pizza createPizza(String type);
image.png
工厂模式用来封装对象的常见,通过让子类决定应该创建的对象,达到将对象创建的过程封装起来的目的。
工厂方法模式:定义了一个创建对象的接口,但由子类决定要实例化的类是哪一个。工厂方法让类把实例化推迟到子类。
工厂模式类图:
image.png
三、抽象工厂模式
抽象工厂模式提供一个接口,用于创建相关或依赖对象的“家族”(敲黑板,重点),而不需要明确指定具体类。
抽象工厂的任务是定义一个负责创建一组产品的接口,这个接口内的每个方法都负责创建一个具体产品,同时利用实现抽象工厂的子类来提供这些具体的做法。
工厂方法用的是继承,而抽象工厂是通过对象的组合来实现。
再通过披萨店的例子,来看看抽象工厂模式。
还是卖披萨的那三步:
1.建立工厂
A.建一个专门生产纽约风味的披萨工厂
abstract class PizzaFactory {
public abstract Pizza createPizza();
}
public class NYPizzaFactory extent PizzaFactory {//继承抽象工厂类,创建具体的实例方法
public Pizza createPizza(String type) {
... //个性化定制纽约口味披萨
return pizza;
}
}
B.制作披萨所用的原料需要保证质量,就需要建立一家生产原料的工厂,这样每家加盟店都从这个原料工厂里进货,确保质量。但是各个加盟店所产披萨的口味不同,所需原料也有细微差别(纽约的芝士和芝加哥的芝士,口味上是不一样的),与建立披萨工厂的思想一样,还是先建立一个原料生产工厂,然后每个区域继承这个工厂,来生产自己各自口味的原料。
定义原料工厂接口,它负责创建所有的原料:
public interface PizzaIngredientFactory{
public Dough createDough(); //生产面团
public Sauce createSauce(); //生产酱料
...
}
那么纽约原料工厂生产的原料就是纽约口味的啦
public class NYPizzaIngredientFactory implements PizzaIngredientFactory {
public Dough createDough() {
return new ThinCrustDough();
}
public Sauce createSauce() {
return new MarinaraSauce();
}
...
}
需要使用原料工厂生产出的原料来制作披萨
public abstract class Pizza {
Dough dough;
Sauce sauce;
...//制作披萨所需的各种原料
abstract void prepare();//把prepare()方法声明成抽象,由不同地区的原料工厂提供原料
//之前的烘烤、切片等工序不变
void back() {
}
void cut() {
}
...
}
之后我们就可以使用原料工厂生产的原料来制作披萨啦,原料的质量得到了保证。
制作一个芝士披萨
public class CheesePizza extends Pizza {
PizzaIngredientFactory ingredientFactory;
public CheesePizza (pizzaIngredientFactory ingredientFactory) {
this.ingredientFactory = ingredientFactory;
}
void prepare() {//从原料工厂里获取原料制作披萨
dough = ingredientFactory.createDough();
Sauce = ingredientFactory.createSauce();
...
}
}
Tips:
image.png
2.开个加盟店
public class NYPizzaStore extends PizzaStore {
Protected Pizza createPizza(String item) {
Pizza pizza = null;
PizzaIngredientFactory ingredientFactory = new NYPizzaIngredientFactory();
if (item.equals(“cheese”)) {
//把工厂传递给每一个披萨,以便比萨从工厂中取得原料
//具体从哪个工厂(纽约工厂?芝加哥工厂?),由上面那行代码决定
pizza = new CheesePizza(ingredientFactory);
} else if ...
return pizza;
}
}
3.卖个纽约风味的芝士披萨
public class PizzaTest {
public Static void main(String[] args) {
PizzaStroe nyStore = new NYPizzaStore();//建个纽约加盟店
Pizza pizza = nyStore.orderPizza(“cheese”);//定个cheese披萨
}
}
看看抽象工厂的类图
image.png
结合披萨店再来看
image.png
结合上面的类图再回顾下抽象工厂的定义,抽象工厂的任务是定义一个负责创建“一组”产品的接口,通过对象的“组合”来实现。
在披萨店的例子中,创建了三个接口:披萨,披萨店,披萨原料工厂,通过组合这三个接口,实现了对各个加盟店的控制:保证披萨的制作工艺,和原料供应
网友评论