转载请注明出处:http://blog.youkuaiyun.com/droyon/article/details/8684094
工厂方法模式:定义了一个创建对象的接口,但由子类决定要实例化的类是哪一个。工厂方法让类把实例化推迟到子类。
案例情景:在简单工厂中的那家买粥的生意非茶好,卖粥的招牌很响,他们想在开两家分店,把招牌租出去,允许分店对粥做改良,更新。
两家分店的名字为CongeeStroeA,CongeeStroeB。CongeeStreA家的大米粥含有皮蛋瘦肉,CongeeStreB家的八宝粥里面还有银耳。我们的总店,CongeeStore去年经营的不错,还是固守陈规。
定义一个工厂方法,这个方法用来处理对象的创建。这个方法的具体实现交由子类来完成。
粥店基类:
public abstract class CongeeStoreBase {
public CongeeStoreBase(){
}
public void buyCongee(String name){
System.out.println("来一份:"+name);
sellCongee(name);
}
private void sellCongee(String name){
Congee congee = getCongee(name);
congee.takeCup();
congee.fillCongee();
congee.sell();
}
protected abstract Congee getCongee(String name);
}
当我们卖出一份粥时,我们需要调用getCongee方法得到一份粥,但这份粥是什么粥,这个类并不关心,它只需将拿到的粥倒入纸杯,递给用户。在这个流程中,CongeeStroeBase并不知道具体的粥类参与进来了。
工厂方法用来处理对象的创建,并将这样的行为封装在子类中。这样,客户程序关于超类的代码就和子类对象创建解耦了。它通过子类来决定实例化那个对象,以此达到将对象创建过程封装的目的。
我们看看是如何做到的:
三家粥店:
1、CongeeStore.java
public class CongeeStore extends CongeeStoreBase{
@Override
protected Congee getCongee(String name) {
if(name.equals("大米粥")){
return new Damizhou();
}else if(name.equals("小米粥")){
return new Xiaomizhou();
}else if(name.equals("八宝粥")){
return new Babaozhou();
}else {
return new Congee("null");
}
}
}
2、CongeeStoreA.java
public class CongeeStoreA extends CongeeStoreBase{
@Override
protected Congee getCongee(String name) {
if(name.equals("大米粥")){
return new DamizhouA();
}else if(name.equals("小米粥")){
return new Xiaomizhou();
}else if(name.equals("八宝粥")){
return new Babaozhou();
}else {
return new Congee("null");
}
}
}
3、CongeeStoreB.java
public class CongeeStroeB extends CongeeStoreBase{
@Override
protected Congee getCongee(String name) {
if(name.equals("大米粥")){
return new Damizhou();
}else if(name.equals("小米粥")){
return new Xiaomizhou();
}else if(name.equals("八宝粥")){
return new BabaozhouB();
}else {
return new Congee("null");
}
}
}
第二家分店做的大米粥,第三家分店做的八宝粥与众不同。
粥类的实现:
Congee.java
public class Congee {
private String name;
public Congee(String name){
this.name = name;
}
public void takeCup(){
System.out.println("拿出一个纸杯");
}
public void fillCongee(){
System.out.println("装入"+name);
}
public void sell(){
System.out.println("卖出这杯粥,价格:"+getPrice(name)+"元");
}
private double getPrice(String name){
if(name.equals("大米粥")){return 2;}
if(name.equals("小米粥")){return 2;}
if(name.equals("八宝粥")){return 2.5;}
if(name.equals("黑米粥")){return 2.5;}
return 0;
}
}
Babaozhou.java
public class Babaozhou extends Congee{
public Babaozhou() {
super("八宝粥");
}
}
Xiaomizhou.java
public class Xiaomizhou extends Congee{
public Xiaomizhou() {
super("小米粥");
}
}
DamizhouA.java
public class DamizhouA extends Congee{
public DamizhouA() {
super("大米粥");
}
@Override
public void fillCongee() {
// super.fillCongee();
System.out.println("装入"+"皮蛋瘦肉大米粥");
}
}
BabaozhouB.java
public class BabaozhouB extends Congee{
public BabaozhouB() {
super("八宝粥");
}
@Override
public void fillCongee() {
// TODO Auto-generated method stub
//super.fillCongee();
System.out.println("装入"+"银耳八宝粥");
}
}
测试主类代码:
Test.java
public class Test {
public static void main(String args[]){
//初始化三家店
CongeeStoreBase no1 = new CongeeStore();
CongeeStoreBase no2 = new CongeeStoreA();
CongeeStoreBase no3 = new CongeeStroeB();
//小李想喝大米粥
no2.buyCongee("大米粥");
System.out.println("-----小李不喜欢含有皮蛋的大米粥,他发誓再也不去no2买粥了");
no1.buyCongee("八宝粥");
System.out.println("-----小李发现no1家的八宝粥不错");
no3.buyCongee("八宝粥");
System.out.println("------小李发现no3家的八宝粥含有银耳,他很喜欢,决定以后天天去");
}
}
测试结果:
来一份:大米粥
拿出一个纸杯
装入皮蛋瘦肉大米粥
卖出这杯粥,价格:2.0元
-----小李不喜欢含有皮蛋的大米粥,他发誓再也不去no2买粥了
来一份:八宝粥
拿出一个纸杯
装入八宝粥
卖出这杯粥,价格:2.5元
-----小李发现no1家的八宝粥不错
来一份:八宝粥
拿出一个纸杯
装入银耳八宝粥
卖出这杯粥,价格:2.5元
------小李发现no3家的八宝粥含有银耳,他很喜欢,决定以后天天去
总结:简单工厂模式把对象的创建封装起来,工厂方法创建了一个框架,让子类决定要如何实现。简单工厂不具备工厂方法的弹性。如果增加新产品,简单工厂需要修改代码,而工厂方法可以通过继承工厂,实现虚方法即可,在设计上更有弹性。
依赖倒置原则:要依赖抽象,不要依赖具体类。不能让高层组件依赖低层组件。两者都应该依赖抽象,围绕抽象解问题,也就是面向抽象编程。
具体解释:
粥店买粥的行为,粥店是高层组件,具体的粥是低层组件。从顶端开始分为以下几步 那个纸盒,装粥,卖粥。所以我的粥店必须有具体的粥。但我们不能依赖具体的类。
现在倒置思考方式,从低层开始思考,每一种粥都是粥,所以所有的粥都有共同的一些特性,所以应该抽离出共同点,构建一个接口。这个接口可以调用具体类的所有行为,这样,我们使用工厂模式将初始化具体类抽离出来,这样高层组件依赖接口粥类,低层具体粥类也依赖接口粥类,从而倒置了编码思考方式。