创建者模式-02工厂模式

二、工厂模式

  • 点果汁案例

1. 简单工厂模式

(不属于设计模式,像编程习惯)

1.1 说明
  • 结构:简单工厂包含
    • 抽象产品:定义了产品的规范,描述了产品的主要特性和功能。
    • 具体产品 :实现或者继承抽象产品的子类
    • 具体工厂 :提供了创建产品的方法,调用者通过该方法来获取产品。
1.2 优缺点

优点

封装了创建对象的过程,可以通过参数直接获取对象。把对象的创建和业务逻辑层分开,这样以后就避 免了修改客户代码,如果要实现新产品直接修改工厂类,而不需要在原代码中修改,这样就降低了客户 代码修改的可能性,更加容易扩展

缺点

增加新产品时还是需要修改工厂类的代码,违背了“开闭原则”。

1.3 UML类图

image-20210513161856641

1.4 代码
  • A类果汁
public class AJuice extends Juice {
    @Override
    public String getName() {
        return "A类果汁";
    }
}
  • B类果汁
public class BJuice extends Juice {
    @Override
    public String getName() {
        return "B类果汁";
    }
}
  • 果汁抽象类
public abstract class Juice {
    public abstract String getName();
    public void addSugar(){
        System.out.println("加糖");
    }
    public void addIce(){
        System.out.println("加冰");
    }
    public void addHot(){
        System.out.println("加热");
    }
}
  • 果汁商店类
public class JuiceStore {    public Juice orderJuice(String type){        SimpleJuiceFactory factory = new SimpleJuiceFactory();        Juice juice = factory.creatJuice(type);        juice.addHot();        juice.addIce();        juice.addSugar();        return juice;    }}
  • 果汁工厂类
public class SimpleJuiceFactory {    public Juice creatJuice(String type){        Juice juice = null;        if("A".equalsIgnoreCase(type)){            juice = new AJuice();        }else if("B".equalsIgnoreCase(type)){            juice = new BJuice();        }else {            throw new RuntimeException("不好意思,没有这种果汁");        }        return juice;    }}
  • 客户测试类
public class Client {    public static void main(String[] args) {        JuiceStore store = new JuiceStore();        Juice juice = store.orderJuice("A");        System.out.println(juice.getName());        Juice juice1 = store.orderJuice("B");        System.out.println(juice1.getName());        Juice juice2 = store.orderJuice("C");        System.out.println(juice2.getName());    }}
  • 测试结果
加热加冰加糖A类果汁加热加冰加糖B类果汁Exception in thread "main" java.lang.RuntimeException: 不好意思,没有这种果汁

2. 静态工厂

(不属于设计模式,像编程习惯)

  • 把工厂类中的创建对象的功能定义为静态的
public class SimpleJuiceFactory {
public static Juice creatJuice(String type){
    Juice juice = null;
    if("A".equalsIgnoreCase(type)){
        juice = new AJuice();
    }else if("B".equalsIgnoreCase(type)){
        juice = new BJuice();
    }else {
        throw new RuntimeException("不好意思,没有这种果汁");
    }
    return juice;
  }
}

3. 工厂方法模式

1.1 说明
  • 结构:主要角色
    • 抽象工厂(Abstract Factory):提供了创建产品的接口,调用者通过它访问具体工厂的工厂 方法来创建产品。
    • 具体工厂(ConcreteFactory):主要是实现抽象工厂中的抽象方法,完成具体产品的创建。
    • 抽象产品(Product):定义了产品的规范,描述了产品的主要特性和功能。
    • 具体产品(ConcreteProduct):实现了抽象产品角色所定义的接口,由具体工厂来创建,它同 具体工厂之间一一对应。
1.2 优缺点

优点

  • 用户只需要知道具体工厂的名称就可得到所要的产品,无须知道产品的具体创建过程;

  • 在系统增加新的产品时只需要添加具体产品类和对应的具体工厂类,无须对原工厂进行任何修改, 满足开闭原则;

缺点

  • 每增加一个产品就要增加一个具体产品类和一个对应的具体工厂类,这增加了系统的复杂度。
1.3 UML类图

image-20210513161829250

1.4 代码
  • 创建果汁工厂接口
public interface JuiceFacotry {    //创建果汁对象的方法    Juice createJuice();}
  • 生产A果汁的工厂
public class AFactory implements JuiceFacotry{    @Override    public Juice createJuice() {        return new AJuice();    }}
  • 生产B果汁的工厂
public class BFactory implements JuiceFacotry{    @Override    public Juice createJuice() {        return new BJuice();    }}
  • 果汁类
public abstract class Juice {
    public abstract String getName();

    public void addSugar(){
        System.out.println("加糖");
    }
    public void addIce(){
        System.out.println("加冰");
    }
    public void addHot(){
        System.out.println("加热");
    }
}
  • A、B果汁类
public class AJuice extends Juice{
    @Override
    public String getName() {
        return "A类果汁";
    }
}
public class BJuice extends Juice{

    @Override
    public String getName() {
        return "B类果汁";
    }
}
  • 果汁商店同上
  • 测试类
public class Client {
    public static void main(String[] args) {
        JuiceStore store = new JuiceStore();
        JuiceFacotry facotry1 = new AFactory();
        store.setJuiceFacotry(facotry1);
        Juice juice = store.orderJuice();
        System.out.println(juice.getName());

        JuiceFacotry facotry2 = new BFactory();
        store.setJuiceFacotry(facotry2);
        Juice juice2 = store.orderJuice();
        System.out.println(juice2.getName());
    }
}
  • 测试结果
加糖加冰加热A类果汁加糖加冰加热B类果汁

4. 抽象工厂模式

需求:发生改变,增加A风格的A类甜点、B风格的B类甜点,为了避免类的爆炸(不停的创建类),使用抽象工厂

抽象工厂模式是工厂方法模式的升级版本,工厂方法模式只生产一个等级的产品,而抽象工厂模式可生 产多个等级的产品。

1 说明

产品族和同一级别的观念

image-20210513160852482

结构:主要角色

  • 抽象工厂:提供了创建产品的接口,它包含多个创建产品的方法,可以 创建多个不同等级的产品。
  • 具体工厂:主要是实现抽象工厂中的多个抽象方法,完成具体产品的创 建。
  • 抽象产品:定义了产品的规范,描述了产品的主要特性和功能,抽象工厂模式有多 个抽象产品。
  • 具体产品:实现了抽象产品角色所定义的接口,由具体工厂来创建,它 同具体工厂之间是多对一的关系。

使用场景

  • 当需要创建的对象是一系列相互关联或相互依赖的产品族时,如电器工厂中的电视机、洗衣机、空 调等。
  • 系统中有多个产品族,但每次只使用其中的某一族产品。如有人只喜欢穿某一个品牌的衣服和鞋。
  • 系统中提供了产品的类库,且所有产品的接口相同,客户端不依赖产品实例的创建细节和内部结 构。
2. 优缺点

优点

当一个产品族中的多个对象被设计成一起工作时,它能保证客户端始终只使用同一个产品族中的对象。

缺点

当产品族中需要增加一个新的产品时,所有的工厂类都需要进行修改。

3. UML类图

image-20210513162121210

4. 代码
  • 风格工厂的接口
public interface StyleFactory {    //生产果汁的功能    Juice createJuice();    //生产甜品的功能    SweetFood createSweet();}
  • 果汁类、甜品类、AB果汁类、AB甜品类
public abstract class Juice {    public abstract String getName();    public void addSugar(){        System.out.println("加糖");    }    public void addIce(){        System.out.println("加冰");    }    public void addHot(){        System.out.println("加热");    }}public class AJuice extends Juice {    @Override    public String getName() {        return "A类果汁";    }}public class BJuice extends Juice {    @Override    public String getName() {        return "B类果汁";    }}/** * 甜品抽象类 */public abstract class SweetFood {    public abstract void show();}public class ASweet extends SweetFood{    @Override    public void show() {        System.out.println("A甜品");    }}public class BSweet extends SweetFood{    @Override    public void show() {        System.out.println("B甜品");    }}
  • A类工厂
public class AStyleFactory implements StyleFactory {    @Override    public Juice createJuice() {        return new AJuice();    }    @Override    public SweetFood createSweet() {        return new ASweet();    }}
  • B类工厂
/** * B */public class BStyleFactory implements StyleFactory {    @Override    public Juice createJuice() {        return new BJuice();    }    @Override    public SweetFood createSweet() {        return new BSweet();    }}
  • 测试类
public class Client {    public static void main(String[] args) {        StyleFactory bfactory = new BStyleFactory();        Juice bJuice = bfactory.createJuice();        SweetFood bSweet = bfactory.createSweet();        System.out.println(bJuice.getName());        bSweet.show();        StyleFactory afactory = new AStyleFactory();        Juice aJuice = afactory.createJuice();        SweetFood aSweet = afactory.createSweet();        System.out.println(aJuice.getName());        aSweet.show();    }}
  • 测试结果
B类果汁B甜品A类果汁A甜品

5. 模式扩展(简单工厂+配置文件接触耦合)

1. 说明

​ 可以通过工厂模式+配置文件的方式解除工厂对象和产品对象的耦合。在工厂类中加载配置文件中的全 类名,并创建对象进行存储,客户端如果需要对象,直接进行获取即可。

2. 代码演示
  • 创建一个配置文件
A=DP02工厂模式.DP04ConfigFactory.AJuiceB=DP02工厂模式.DP04ConfigFactory.BJuice
  • 果汁广场改造
public class JuiceFactory {
    private static HashMap<String,Juice> map = new HashMap<>();
    static {
        Properties prop = new Properties();
        try {

            prop.load(new InputStreamReader(JuiceFactory.class.getClassLoader().getResourceAsStream("bean.properties"),"GBK"));

            //拿到里面所有的键
            Set<Object> keys = prop.keySet();
            for (Object key :
                    keys) {
                String className = prop.getProperty((String) key);
                //通过反射创建对象
                Class clazz = Class.forName(className);

                Juice juice = (Juice)clazz.newInstance();
                //将名称和对象存储到容器中
                map.put((String)key,juice);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    //根据名称获取对象
    public static Juice createJuice(String name){
        return map.get(name);
    }
}
  • 测试类
public class Client {
    public static void main(String[] args) {
        Juice juice = JuiceFactory.createJuice("A");
        System.out.println(juice.getName());
        System.out.println("============");
        Juice juice1 = JuiceFactory.createJuice("B");
        System.out.println(juice1.getName());
    }
}
3. 好处
  • 静态成员变量用来存储创建的对象(键存储的是名称,值存储的是对应的对象),而读取配置文件以及 创建对象写在静态代码块中,目的就是只需要执行一次。

6. 实际应用案例

1. Iterator方法

image-20210514183204899

  • Collection接口是抽象工厂类
  • ArrayList是具体的工厂类;
  • Iterator接口是抽象商品类,
  • ArrayList类中的Iter内部类是具体的商品类。在具体的工厂类中iterator()方法创建具体的商品 类的对象。
2. 其他案例
  1. DateForamt类中的getInstance()方法使用的是工厂模式;
  2. Calendar类中的getInstance()方法使用的是工厂模式;

员变量用来存储创建的对象(键存储的是名称,值存储的是对应的对象),而读取配置文件以及 创建对象写在静态代码块中,目的就是只需要执行一次。

6. 实际应用案例

1. Iterator方法

[外链图片转存中…(img-vlvKyHFk-1621781102112)]

  • Collection接口是抽象工厂类
  • ArrayList是具体的工厂类;
  • Iterator接口是抽象商品类,
  • ArrayList类中的Iter内部类是具体的商品类。在具体的工厂类中iterator()方法创建具体的商品 类的对象。
2. 其他案例
  1. DateForamt类中的getInstance()方法使用的是工厂模式;
  2. Calendar类中的getInstance()方法使用的是工厂模式;
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值