设计原则:(依赖倒置原则)要依赖抽象,不要依赖具体类。
在应用工厂方法之后,高层组件(PizzaStore)和低层组件(就是具体的披萨类型)都依赖了Pizza这个抽象类。
1.变量不可以持有具体类的引用。(使用如果new,就会持有具体类的引用。)
2.不要让类派生自具体类。(如果派生自具体类,你就会依赖具体类了)
3.不要覆盖基类中已实现的方法。(如果覆盖基类已实现的方法,基类就不是一个真正适合被继承的抽象,基类红已实现的方法应该被所有子类所共用)
进一步学习:
围绕第三点来展开,当我们需要覆盖基类中已实现的方法时,那么代表该方法的实现必须是对每个子类都是有必要去覆盖实现的,这样还能利用工厂模式来解决~~~
注意了Pizza类中方法prepare():原料的准备。现在加盟店要建立自己原料工厂,但是为了仍然沿用一套代码,那就是每个子类需要去覆盖prepare()方法,那就把prepare()方法定义成抽象的即可。
Pizza类标红区域即为原料,这里的每一种原料都是一个对象,而且不是具体对象,每个加盟店的每一种原料对象都继承与最高层次的原料对象,每个加盟店由于地理位置不同,所得到的原料也不同,所以每一个加盟店都有属于自己的原料工厂,但是所有的原料工厂都应该是实现一个共同的接口得到的,这样总原料工厂才能方便管理。
所以为工厂定义一个接口,这个接口负责创建所有的
public interface PizzaIngredientFactory {
public Dough createDough();
public Sauce createSauce();
public Veggies[] createVeggies();
public Pepperoni createPepperoni();
public Clams createClam();
}
public abstract class Pizza {
String name;
Dough dough;//面团
Sauce sauce;//酱
Veggies veggies[];//素菜
Pepperoni pepperoni;//洋葱
Clams clam;//蛤
public abstract void prepare();
public void bake(){
System.out.println("bake");
}
public void cut(){
System.out.println("cut");
}
public void box(){
System.out.println("box");
}
public String getName(){
return name;
}
}
下面代码是建立了一个纽约的原料工厂:
public class NYPizzaIngredientFactory implements PizzaIngredientFactory {
@Override
public Dough createDough() {
// TODO Auto-generated method stub
return new NYDough();
}
@Override
public Sauce createSauce() {
// TODO Auto-generated method stub
return new NYSauce();
}
@Override
public Veggies[] createVeggies() {
// TODO Auto-generated method stub
Veggies Veggies[]={new Garlic(),new Onion()};
return Veggies;
}
@Override
public Pepperoni createPepperoni() {
// TODO Auto-generated method stub
return new NYPepperoni();
}
@Override
public Clams createClam() {
// TODO Auto-generated method stub
return new NYClams();
}
}
public class NYClams extends Clams {
}
public class NYDough extends Dough {
}
public class NYPepperoni extends Pepperoni {
}
public class NYSauce extends Sauce {
}
public class Garlic extends Veggies {
}
public class Onion extends Veggies {
}
编写一个具有纽约风味且是纽约原料工厂制作的披萨类:
public class NYStyleChessPizza extends Pizza {
PizzaIngredientFactory ingredientFactory;
public NYStyleChessPizza(PizzaIngredientFactory ingredientFactory){
this.ingredientFactory=ingredientFactory;
}
@Override
public void prepare() {
// TODO Auto-generated method stub
dough=ingredientFactory.createDough();
sauce=ingredientFactory.createSauce();
clam=ingredientFactory.createClam();
}
}
具体的披萨类写好了后,还需要看看纽约的披萨店,因为披萨制作是在披萨店进行发起的。(具体的披萨类需要传入原料工厂的具体实现类,所以需要改变披萨店类)
public class NYStorePizzStore extends PizzaStore {
@Override
protected Pizza createPizza(String type) {
Pizza pizza=null;
PizzaIngredientFactory NYPizzaIngredientFactory=new NYPizzaIngredientFactory();
if(type.equals("cheese")){
pizza =new NYStyleCheesePizza(NYPizzaIngredientFactory);
}
return pizza;
}
}
通过上面一系列,终于完成了原料工厂的搭建,我们回顾一下过程:
1.由于每一个加盟店原料不同,所以必须对Pizza类中原料准备方法进行抽象,使得每一个具体的Pizza类都能进行重写。
2.因为这个方法的抽象,而引发了原料工厂接口,并为每个加盟店都提供具体的原料工厂。即最终的产物为一个具体的产品。
抽象工厂模式:提供一个接口,用于创建相关或依赖对象的家族,而不需要明确指定具体类。