《HeadFirst设计模式》(4)——工厂模式

前言

当我们使用new实例化具体类时,针对的是实现编程,而不是接口,这会让代码缺乏弹性。比如`

Pizza chickenPizza = new chickenPizza();

虽然左边使用了接口,但右面还是得建立具体类的实例。当有一群具体类并且需要运行时才确定需要实例化哪一个时,通常会写出如下代码:

		Pizza Pizza;
        if (customer want chickenPizza){
            pizza = new ChickenPizza();
        }else if (customer want cheesePizza){
            pizza = new CheesePizza();
        } else if (customer want clamPizza) {
            pizza = new ClamPizza();
        }

一旦有变化或者扩展,必须要打开这段代码进行修改,比如需要加入新的产品或者一部分产品不需要了。所以,按照封装变化的原则,我们应该把实例化具体类的这部分代码封装起来。

简单工厂模式

简单工厂其实并不能算是一种模式,更像是一种编程习惯。将创建实例的任务放到简单工厂对象中。

public class PizzaStore {
    SimplePizzaFactory simplePizzaFactory;

    public PizzaStore(SimplePizzaFactory simplePizzaFactory) {
        this.simplePizzaFactory = simplePizzaFactory;
    }
    public Pizza orderPizza(String type) {
    	//将实例pizza的代码放到简单工厂中
        Pizza pizza = simplePizzaFactory.createPizza(type);
        
        pizza.prepare();
        pizza.bake();
        pizza.cut();
        pizza.box();
        return pizza;
    }
}
public class SimplePizzaFactory {
    public Pizza createPizza(String type) {
        switch (type) {
            case "cheese":
                return new cheesePizza();
            case "Bacon":
                return new baconPizza();
            default:
                return null;
        }
    }
}

看起来似乎只是将修改换了个地方,而不是不需要修改。其实一个简单工厂通常并不是只有一个客户,而且我们应该将具体实例化过程从客户中移除。(更符合单一职责原则)
常见的使用方式是将简单工厂中创建对象的方法声明为静态方法,这样就不用实例化简单工厂对象,但不能通过继承改变创建方法。

工厂方法模式

模式定义

工厂方法模式 定义了一个创建对象的接口,但由子类决定实例化的类是哪一个。工厂方法把实例化推迟到子类。
所谓的“让子类决定实例化的类”并不是指允许子类在运行时做决定,而是指抽象工厂不知道实际创建的产品是什么。选择了使用哪个子类,自然就决定了实际创建的产品是什么。

设计原则

依赖倒置原则。 要依赖抽象,不要依赖具体类。
在这里插入图片描述
避免违反依赖倒置原则的几个指导方针:

  • 变量不可以持有具体类的引用。如果使用new,就含有了具体类的引用,试试工厂方法。
  • 不要让类派生自具体类。如果派生自具体类,就会依赖具体类。试着派生自接口或抽象类。
  • 不要覆盖基类中已经实现的方法。基类中已经实现的方法应当被所有子类共享,否则就不适合作为基类。

问题场景

有一个Pizza连锁店系统,总店希望各分店制作的pizza具有当地特色,比如同样是芝士披萨,纽约的披萨饼薄,芝加哥的饼厚。但是制作流程要和总店一致:烘烤、切片、装盒的方式。

类图

其实这个例子不怎么好,这里的工厂方法为“参数化工厂方法”,每个工厂负责创建多个产品(纽约披萨店要创建芝士、蛤蜊等多种口味的披萨)。正常使用的是每个工厂只产生一种产品,不需要参数,有新产品时增加相应的工厂。
在这里插入图片描述

代码

在这里插入图片描述

//工厂
public abstract class PizzaStore {
	//对产品进行操作,不需要关心具体是什么产品
    public Pizza orderPizza(String type) {
        Pizza pizza = createPizza(type);
        pizza.prepare();
        pizza.bake();
        pizza.cut();
        pizza.box();
        return pizza;
    }
    //工厂方法————这个方法就是工厂
    public abstract Pizza createPizza(String type);
}
//工厂子类
public class NYPizzaStore extends PizzaStore {
    @Override
    //参数化工厂方法,一个工厂负责创建多个产品
    public Pizza createPizza(String type) {
        switch (type) {
            case "Cheese":
                return new NYCheesePiz();
            case "Bacon":
                return new NYBaconPizza();
            default:
                return null;
        }
    }
}
//抽象产品
public class Pizza {

    public void prepare() {System.out.println( "Pizza is preparing...");}

    public void bake() {}

    public void cut() {}

    public void box() {}
}
//具体产品
public class NYCheesePiz extends Pizza {
    public NYCheesePiz() {}
}
//具体产品
public class NYBaconPizza extends Pizza {
}

抽象工厂模式

问题场景

不同地区的pizza店所采用的原料一般也不一样,比如纽约店使用新鲜的蛤蜊,芝加哥店使用冷冻的蛤蜊,它们使用的面粉也不一样······我们需要建造工厂来生产pizza的原料家族,并在制作pizza时使用这些工厂提供原料。

模式定义

抽象工厂模式 提供一个接口,用于创建相关或依赖对象的家族,而不需要明确指定具体类。

  • 抽象工厂允许客户使用抽象的接口来创建一组相关的产品,而不需要知道(或关心)实际产出的具体产品是什么。
  • 客户持有抽象工厂的引用,运行时使用具体工厂。

类图

在这里插入图片描述
在这里插入图片描述

代码

在这里插入图片描述

//抽象工厂
public interface CondiAbstrFactory {
	//各个原料使用单独的工厂方法创建
    public Meet createMeet();

    public Cheese createCheese();

    public Clam createClam();
}
public class NYCondiFactory implements CondiAbstrFactory {
    @Override
    public Meet createMeet() {
        return new NYMeet();
    }

    @Override
    public Cheese createCheese() {
        return new NYCheese();
    }

    @Override
    public Clam createClam() {
        return new NYClam();
    }

}
public abstract class Pizza {
    Cheese cheese;
    Meet meet;
    Clam clam;
    public abstract void prepare();
    public void bake();
}

通过工厂对象创建产品

//使用工厂创建原料
public class CheesePizza extends Pizza {

    public CheesePizza(CondiAbstrFactory condiAbstrFactory) {
        this.cheese = condiAbstrFactory.createCheese();
        this.meet = condiAbstrFactory.createMeet();
    }

    @Override
    public void prepare() {

    }
}
//和上面一样,用工厂方法创建pizza
public abstract class PizzaStore {
    public Factory.AbstractFactory.Pizza orderPizza(String type) {
        Pizza pizza = createPizza(type);
        return pizza;
    }

    //工厂方法
    public abstract Factory.AbstractFactory.Pizza createPizza(String type);
}
public class NYPizzaStore extends PizzaStore {
    //使用抽象工厂的具体工厂
    //通过传入工厂制造不同的产品
    @Override
    public Pizza createPizza(String type) {
        CondiAbstrFactory condiAbstrFactory = new NYCondiFactory();
        switch (type) {
            case "cheese":
                return new CheesePizza(condiAbstrFactory);
                //return new NYCheesePizza();
            case "clam":
                return new ClamPizza(condiAbstrFactory);
                //return new NYClamPizza();
            default:
                return null;
        }
    }
}

工厂方法模式v.s. 抽象工厂模式

工厂方法模式 抽象工厂模式
实现方式工厂方法模式使用继承,将具体类型的实例化放到子类中。 抽象工厂模式使用组合,抽象工厂提供创建产品家族(或一组相关产品)的工厂方法,具体工厂实现创建这些产品的方法。通过抽象工厂中的方法创建对象。客户使用具体工厂。
适用场景不知道将来要实例化哪些具体类型时可以使用工厂方法。 有一组相关产品要创建时使用抽象工厂。将这些创建的方法放到一个接口中。
开闭原则支持度高,每增加一个产品就增加一个工厂。支持度低,增加产品时要修改接口。
抽象工厂模式中的具体工厂实现工厂方法创建产品
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值