当我们只用new去创建一个类时,我们就在针对这个具体类编程。如果能够不使用具体类,而是针对接口编程,将会对以后扩展有很大方便。
情景:
你是一个披萨店的老板,披萨有很多种类。
我们可能需要这么做
</span><span style="color: #0000ff;">if</span> (type == <span style="color: #800000;">A</span><span style="color: #000000;">) {
pizza </span>= <span style="color: #0000ff;">new</span><span style="color: #000000;"> APizza();
} </span><span style="color: #0000ff;">else</span> <span style="color: #0000ff;">if</span> (type == <span style="color: #800000;">B</span><span style="color: #000000;">) {
pizza </span>= <span style="color: #0000ff;">new</span><span style="color: #000000;"> BPizza();
} </span><span style="color: #0000ff;">else</span> <span style="color: #0000ff;">if</span> (type == <span style="color: #800000;">C</span><span style="color: #000000;">) {
pizza </span>= <span style="color: #0000ff;">new</span><span style="color: #000000;"> CPizza();
}
... </span><span style="color: #008000;">//</span><span style="color: #008000;"> 制作披萨订单的其他操作</span>
}
但是以后我们可能会有D,E,F....之列的更多的披萨。我们必须重新修改这份代码。
根据“封装变化”的设计原则,我们需要把创建对象的部分封装起来。
</span><span style="color: #0000ff;">if</span> (type.equals("A"<span style="color: #000000;">)) {
pizza </span>= <span style="color: #0000ff;">new</span><span style="color: #000000;"> APizza();
} </span><span style="color: #0000ff;">else</span> <span style="color: #0000ff;">if</span> (type.equals("B"<span style="color: #000000;">)) {
pizza </span>= <span style="color: #0000ff;">new</span><span style="color: #000000;"> BPizza();
} </span><span style="color: #0000ff;">else</span> <span style="color: #0000ff;">if</span> (type.equals("C"<span style="color: #000000;">)) {
pizza </span>= <span style="color: #0000ff;">new</span><span style="color: #000000;"> CPizza();
}
</span><span style="color: #0000ff;">return</span><span style="color: #000000;"> pizza;
}
}
这样在制作订单时只需在工厂取一个Pizza就可以了。
</span><span style="color: #0000ff;">public</span><span style="color: #000000;"> PizzaStore(SimplePizzaFactory factory) {
</span><span style="color: #0000ff;">this</span>.factory =<span style="color: #000000;"> factory;
}
</span><span style="color: #0000ff;">public</span><span style="color: #000000;"> Pizza orderPizza(String type) {
Pizza pizza;
pizza </span>=<span style="color: #000000;"> factory.createPizza(type);
pizza.prepare();
pizza.bake();
pizza.cut();
pizza.<a href="https://www.jb51.cc/tag/Box/" target="_blank" class="keywords">Box</a>();
</span><span style="color: #0000ff;">return</span><span style="color: #000000;"> pizza;
}
}
现在有很地区要建立披萨店的分店,你希望所有的店都有相同的流程,但是不同的地区会有不同的口味,比如有些地方只吃DEF口味的披萨,也就是说不同地区要有不同的工厂,没有方法把Pizza的制作活动全部局限于PizzaStore类呢?
方法是把createPizza放进PizzaStore类中,并设置成抽象方法,具体实现由每一个地区的子类完成。
</span><span style="color: #0000ff;">public</span><span style="color: #000000;"> Pizza orderPizza(String type) {
Pizza pizza;
pizza </span>=<span style="color: #000000;"> createPizza(type);
pizza.prepare();
pizza.bake();
pizza.cut();
pizza.<a href="https://www.jb51.cc/tag/Box/" target="_blank" class="keywords">Box</a>();
</span><span style="color: #0000ff;">return</span><span style="color: #000000;"> pizza;
}
</span><span style="color: #0000ff;">abstract</span><span style="color: #000000;"> Pizza createPizza(String type);
}
方法用来处理对象的创建,并将这样的行为封装在子类中。这样,客户程序中关于超类的代码就和子类创建对象的代码解耦了。
Product factoryMethod(String type)
方法模式:定义了一个创建对象的接口,但由子类决定要实例化的类是哪一个。工厂方法让类把实例化推迟到子类。
我们最一开始的代码,PizzaStore的实现是依赖于具体Pizza类的,使用工厂模式后,它已经不再依赖于具体的披萨类,也就是减少了对具体类的依赖。
设计原则:依赖倒置原则(Dependency Inverseion Principle)
要依赖抽象,不要依赖具体类。
这个原则说明了,不要让高层组件依赖底层组件,而且,不管高层组件还是底层组件,两者都应该依赖抽象。
使用了工厂方法模式之后,PizzaStore类依赖Pizza这个接口,而具体的APizza,BPizza等具体披萨类也依赖于Pizza这个接口,这就是一种依赖倒置。
………………
现在又有一个新的问题
就是具体Pizza的制作。上面没有写具体披萨的制作过程,默认都是一样的。但是!不同地区用到原料也可能有不同,例如A地产辣椒和B地是不一样的,于是,我们还应该给Pizza写一个原料工厂~~~
首先为工厂定义一个接口
为每一个地区创建一个原料工厂,比如纽约的原料工厂
@Override
</span><span style="color: #0000ff;">public</span><span style="color: #000000;"> Dough createDough() {
</span><span style="color: #0000ff;">return</span> <span style="color: #0000ff;">new</span><span style="color: #000000;"> ThinCrustDough();
}
@Override
</span><span style="color: #0000ff;">public</span><span style="color: #000000;"> Sauce createSauce() {
</span><span style="color: #0000ff;">return</span> <span style="color: #0000ff;">new</span><span style="color: #000000;"> MarinaraSauce();
}
@Override
</span><span style="color: #0000ff;">public</span><span style="color: #000000;"> Cheese createCheese() {
</span><span style="color: #0000ff;">return</span> <span style="color: #0000ff;">new</span><span style="color: #000000;"> ReggianoCheese();
}
@Override
</span><span style="color: #0000ff;">public</span><span style="color: #000000;"> Veggies[] createVeggies() {
Veggies[] veggies </span>= { <span style="color: #0000ff;">new</span> Garlic(),<span style="color: #0000ff;">new</span> Onion(),<span style="color: #0000ff;">new</span> Mushroom(),<span style="color: #0000ff;">new</span><span style="color: #000000;"> RedPepper() };
</span><span style="color: #0000ff;">return</span><span style="color: #000000;"> veggies;
}
@Override
</span><span style="color: #0000ff;">public</span><span style="color: #000000;"> Pepperoni createPepperoni() {
</span><span style="color: #0000ff;">return</span> <span style="color: #0000ff;">new</span><span style="color: #000000;"> SlicedPepperni();
}
@Override
</span><span style="color: #0000ff;">public</span><span style="color: #000000;"> Clams createClam() {
</span><span style="color: #0000ff;">return</span> <span style="color: #0000ff;">new</span><span style="color: #000000;"> FreshClams();
}
}
抽象的Pizza类
String name;
Dough dough;
Sauce sauce;
Veggies veggies[];
Cheese cheese;
Pepperoni pepperoni;
Clams clams;
</span><span style="color: #0000ff;">abstract</span> <span style="color: #0000ff;">void</span><span style="color: #000000;"> prepare();
</span><span style="color: #0000ff;">public</span> <span style="color: #0000ff;">void</span><span style="color: #000000;"> bake() {
System.out.println(</span>"Bake for 25 minutes at 350."<span style="color: #000000;">);
}
</span><span style="color: #0000ff;">public</span> <span style="color: #0000ff;">void</span><span style="color: #000000;"> cut() {
System.out.println(</span>"Cutting the pizza into diagonal slices."<span style="color: #000000;">);
}
</span><span style="color: #0000ff;">public</span> <span style="color: #0000ff;">void</span><span style="color: #000000;"> <a href="https://www.jb51.cc/tag/Box/" target="_blank" class="keywords">Box</a>() {
System.out.println(</span>"Place pizza in official PizzaStore <a href="https://www.jb51.cc/tag/Box/" target="_blank" class="keywords">Box</a>."<span style="color: #000000;">);
}
</span><span style="color: #0000ff;">void</span><span style="color: #000000;"> setName(String name) {
</span><span style="color: #0000ff;">this</span>.name =<span style="color: #000000;"> name;
}
String getName() {
</span><span style="color: #0000ff;">return</span><span style="color: #000000;"> name;
}
</span><span style="color: #0000ff;">public</span><span style="color: #000000;"> String toString() {
</span><span style="color: #0000ff;">return</span><span style="color: #000000;"> name;
}
}
具体的Pizza类。每个Pizza的制作流程其实是一样的。只有原料不同,同时原料会和地点有关。为具体的类添加一个原料工厂。
PizzaIngredientFactory ingredientFactory;
</span><span style="color: #0000ff;">public</span><span style="color: #000000;"> CheesePizza(PizzaIngredientFactory ingredientFactory) {
</span><span style="color: #0000ff;">this</span>.ingredientFactory =<span style="color: #000000;"> ingredientFactory;
}
@Override
</span><span style="color: #0000ff;">void</span><span style="color: #000000;"> prepare() {
System.out.println(</span>"Preparing " +<span style="color: #000000;"> name);
dough </span>=<span style="color: #000000;"> ingredientFactory.createDough();
sauce </span>=<span style="color: #000000;"> ingredientFactory.createSauce();
cheese </span>=<span style="color: #000000;"> ingredientFactory.createCheese();
}
}
纽约的PizzaStore类
@Override
Pizza createPizza(String item) {
Pizza pizza </span>= <span style="color: #0000ff;">null</span><span style="color: #000000;">;
PizzaIngredientFactory ingredientFactory </span>= <span style="color: #0000ff;">new</span><span style="color: #000000;"> NYPizzaIngredientFactory();
</span><span style="color: #0000ff;">if</span> (item.equals("cheess"<span style="color: #000000;">)) {
pizza </span>= <span style="color: #0000ff;">new</span><span style="color: #000000;"> ChessPizza(ingredientFactory);
} </span><span style="color: #0000ff;">else</span> <span style="color: #0000ff;">if</span> (item.equals("veggie"<span style="color: #000000;">)) {
pizza </span>= <span style="color: #0000ff;">new</span><span style="color: #000000;"> VeggiePizza();
pizza.setName(</span>"New York Style Veggie Pizza."<span style="color: #000000;">);
}
</span><span style="color: #008000;">//</span><span style="color: #008000;"> else if .... 还有其他种类的Pizza </span>
<span style="color: #0000ff;">return</span><span style="color: #000000;"> pizza;
}
}
完成~~
我们引入了新类型的工厂,也就是所谓的抽象工厂,来创建披萨家族。
抽象工程模式:提供一个接口,用于创建相关或依赖对象的家族,而不需要明确指定具体类。
抽象工厂允许客户使用抽象类的接口来创建一组相关的产品,而不需要知道(或关心)实际产出的具体产品是什么。这样一来,客户就从具体产品中被解耦。
类图
工厂方法模式通过继承,而抽象工厂模式是通过组合实现。
抽象工厂是用来创建一个产品家族的抽象类型,可以把一群相关产品集合起来。
原文链接:https://www.f2er.com/javaschema/69831.html