【设计模式】23种设计模式——工厂模式(原理讲解+应用场景介绍+案例介绍+Java代码实现)

news2024/11/26 13:32:28

工厂模式

需求了解

看一个披萨的项目:要便于披萨种类的扩展,要便于维护

  • 披萨的种类很多(比如 GreekPizz、CheesePizz 等)
  • 披萨的制作有 prepare(准备材料),bake(烘焙),cut(切割),box(打包)
  • 完成披萨店订购功能

传统方式实现

在这里插入图片描述

实体类

package com.atguigu.factory.tradition.pizza;

/**
 * 将Pizza 类做成抽象
 */
public abstract class Pizza {
    /**
     * 名字
     */
    protected String name;


    /**
     * 准备原材料, 不同的披萨不一样,因此,我们做成抽象方法
     */
    public abstract void prepare();


    public void bake() {
        System.out.println(name + " baking;");
    }

    public void cut() {
        System.out.println(name + " cutting;");
    }

    //打包
    public void box() {
        System.out.println(name + " boxing;");
    }

    public void setName(String name) {
        this.name = name;
    }
}
package com.atguigu.factory.tradition.pizza;

public class CheesePizza extends Pizza {

   @Override
   public void prepare() {
      // TODO Auto-generated method stub
      System.out.println(" 准备CheesePizza ");
   }

}
package com.atguigu.factory.tradition.pizza;

public class GreekPizza extends Pizza {

   @Override
   public void prepare() {
      // TODO Auto-generated method stub
      System.out.println("准备GreekPizza");
   }

}
package com.atguigu.factory.tradition.pizza;

public class PepperPizza extends Pizza {

   @Override
   public void prepare() {
      // TODO Auto-generated method stub
      System.out.println("准备PepperPizza");
   }

}

订购类

package com.atguigu.factory.tradition.order;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;


import com.atguigu.factory.tradition.pizza.CheesePizza;
import com.atguigu.factory.tradition.pizza.GreekPizza;
import com.atguigu.factory.tradition.pizza.PepperPizza;
import com.atguigu.factory.tradition.pizza.Pizza;

public class OrderPizza {

   public OrderPizza() {
      Pizza pizza = null;
      String orderType; // 订购披萨的类型
      do {
         orderType = getType();
         if (orderType.equals("greek")) {
            pizza = new GreekPizza();
            pizza.setName(" greek pizza ");
         } else if (orderType.equals("cheese")) {
            pizza = new CheesePizza();
            pizza.setName(" cheese pizza ");
         } else if (orderType.equals("pepper")) {
            pizza = new PepperPizza();
            pizza.setName(" pepper pizza ");
         } else {
            break;
         }
         //输出pizza 制作过程
         pizza.prepare();
         pizza.bake();
         pizza.cut();
         pizza.box();

      } while (true);
   }

   /**
    * 写一个方法,可以获取客户希望订购的披萨种类
    * @return
    */
   private String getType() {
      try {
         BufferedReader strin = new BufferedReader(new InputStreamReader(System.in));
         System.out.println("input pizza type:");
         String str = strin.readLine();
         return str;
      } catch (IOException e) {
         e.printStackTrace();
         return "";
      }
   }

}

客户端

package com.atguigu.factory.tradition.order;

//相当于一个客户端,发出订购
public class PizzaStore {

    public static void main(String[] args) {
        new OrderPizza();
    }

}

分析

  • 优点是比较好理解,简单易操作
  • 缺点是违反了设计模式的ocp原则,即对扩展开放,对修改关闭。即当我们给类增加新功能的时候,尽量不修改代码,或者尽可能少修改代码
  • 比如我们这时要新增加一个Pizza的种类(Cheese披萨),我们需要做如下修改

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-INzJ96jq-1689236134050)(assets/1689236101251-1.png)]

改进

  • 修改代码可以接受,但是如果我们在其它的地方也有创建Pizza的代码,就意味着,也需要修改,而创建pizza的代码,往往有多处
  • 把创建Pizza对象封装到一个类中,这样我们有新的Pizza种类时,只需要修改该类就可,其它有创建Pizza对象的代码就不需要修改了(简单工厂模式)

简单工厂模式

介绍

  • 简单工厂模式是属于创建型模式,是工厂模式的一种。简单工厂模式是由个工厂对象决定创建出哪一种产品类的实例。简单工厂模式是工厂模式家族中最简单实用的模式
  • 简单工厂模式:定义了一个创建对象的类,由这个类来封装实例化对象的行为(代码)
  • 在软件开发中,当我们会用到大量的创建某种、某类或者某批对象时,就会使用到工厂模式

在这里插入图片描述

实现

简单工厂模式

【工厂类】

package com.atguigu.factory.simplefactory.pizzastore.order;

import com.atguigu.factory.simplefactory.pizzastore.pizza.CheesePizza;
import com.atguigu.factory.simplefactory.pizzastore.pizza.GreekPizza;
import com.atguigu.factory.simplefactory.pizzastore.pizza.PepperPizza;
import com.atguigu.factory.simplefactory.pizzastore.pizza.Pizza;

//简单工厂类
public class SimpleFactory {

    /**
     * 根据orderType 返回对应的Pizza 对象
     *
     * @param orderType
     * @return
     */
    public Pizza createPizza(String orderType) {

        Pizza pizza = null;

        System.out.println("使用简单工厂模式");
        if (orderType.equals("greek")) {
            pizza = new GreekPizza();
            pizza.setName(" 希腊披萨 ");
        } else if (orderType.equals("cheese")) {
            pizza = new CheesePizza();
            pizza.setName(" 奶酪披萨 ");
        } else if (orderType.equals("pepper")) {
            pizza = new PepperPizza();
            pizza.setName("胡椒披萨");
        }

        return pizza;
    }

}

【订购类】

package com.atguigu.factory.simplefactory.pizzastore.order;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;


import com.atguigu.factory.simplefactory.pizzastore.pizza.Pizza;

public class OrderPizza {

    /**
     * 定义一个简单工厂对象,这里使用的是聚合关系,如果想换成组合关系的话,直接new就行
     */
    SimpleFactory simpleFactory;
    Pizza pizza = null;

    //构造器
    public OrderPizza(SimpleFactory simpleFactory) {
        setFactory(simpleFactory);
    }

    public void setFactory(SimpleFactory simpleFactory) {
        //用户需要预定什么pizza,用户输入
        String orderType = "";
        //设置简单工厂对象
        this.simpleFactory = simpleFactory;

        do {
            orderType = getType();
            pizza = this.simpleFactory.createPizza(orderType);

            //输出pizza
            if (pizza != null) {
                //--if--订购成功
                pizza.prepare();
                pizza.bake();
                pizza.cut();
                pizza.box();
            } else {
                System.out.println(" 订购披萨失败 ");
                break;
            }
        } while (true);
    }

    /**
     * 写一个方法,可以获取客户希望订购的披萨种类
     *
     * @return
     */
    private String getType() {
        try {
            BufferedReader strin = new BufferedReader(new InputStreamReader(System.in));
            System.out.println("input pizza type:");
            String str = strin.readLine();
            return str;
        } catch (IOException e) {
            e.printStackTrace();
            return "";
        }
    }

}

【主类】

package com.atguigu.factory.simplefactory.pizzastore.order;

//相当于一个客户端,发出订购
public class PizzaStore {

   public static void main(String[] args) {
      //使用简单工厂模式
      new OrderPizza(new SimpleFactory());
      System.out.println("~~退出程序~~");
      
   }

}

【运行】

input pizza type:
greek
使用简单工厂模式
 给希腊披萨 准备原材料 
 希腊披萨  baking;
 希腊披萨  cutting;
 希腊披萨  boxing;
input pizza type:
cheese
使用简单工厂模式
 给制作奶酪披萨 准备原材料 
 奶酪披萨  baking;
 奶酪披萨  cutting;
 奶酪披萨  boxing;
input pizza type:
静态工厂模式(简单工厂模式的另外一种实现方式)

【工厂类】

package com.atguigu.factory.simplefactory.pizzastore.order;

import com.atguigu.factory.simplefactory.pizzastore.pizza.CheesePizza;
import com.atguigu.factory.simplefactory.pizzastore.pizza.GreekPizza;
import com.atguigu.factory.simplefactory.pizzastore.pizza.PepperPizza;
import com.atguigu.factory.simplefactory.pizzastore.pizza.Pizza;

//简单工厂类
public class SimpleFactory {
    /**
     * 简单工厂模式 也叫 静态工厂模式(使用静态方法)
     * @param orderType
     * @return
     */
    public static Pizza createPizza2(String orderType) {

        Pizza pizza = null;

        System.out.println("使用简单工厂模式2");
        if (orderType.equals("greek")) {
            pizza = new GreekPizza();
            pizza.setName(" 希腊披萨 ");
        } else if (orderType.equals("cheese")) {
            pizza = new CheesePizza();
            pizza.setName(" 奶酪披萨 ");
        } else if (orderType.equals("pepper")) {
            pizza = new PepperPizza();
            pizza.setName("胡椒披萨");
        }

        return pizza;
    }

}

【订购类】

package com.atguigu.factory.simplefactory.pizzastore.order;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;

import com.atguigu.factory.simplefactory.pizzastore.pizza.Pizza;

public class OrderPizza2 {
    Pizza pizza = null;
    String orderType = "";

    public OrderPizza2() {
        do {
            orderType = getType();
            //调用静态方法,类.方法名
            pizza = SimpleFactory.createPizza2(orderType);

            if (pizza != null) {
                //--if--  订购成功
                pizza.prepare();
                pizza.bake();
                pizza.cut();
                pizza.box();
            } else {
                System.out.println(" 订购披萨失败 ");
                break;
            }
        } while (true);
    }

    /**
     * 写一个方法,可以获取客户希望订购的披萨种类
     *
     * @return
     */
    private String getType() {
        try {
            BufferedReader strin = new BufferedReader(new InputStreamReader(System.in));
            System.out.println("input pizza 种类:");
            String str = strin.readLine();
            return str;
        } catch (IOException e) {
            e.printStackTrace();
            return "";
        }
    }
}

【主类】

package com.atguigu.factory.simplefactory.pizzastore.order;

//相当于一个客户端,发出订购
public class PizzaStore {

   public static void main(String[] args) {
      new OrderPizza2();
   }

}

工厂方法模式

新需求

披萨项目新的需求:客户在点披萨时,可以点不同口味的披萨,比如 北京的奶酪pizza、北京的胡椒pizza、或者是伦敦的奶略pizza、伦敦的胡椒pizza。(即不只是有Pizza种类的区别,还有地点的区别)

【思路一】

使用简单工厂模式,创建不同的简单工厂类,比如BJPizzaSimpleFactory、LDPizzaSimpleFactory 等等,从当前这个案例来说,也是可以的,但是考虑到项目的规模,以及软件的可维护性、可扩展性并不是特别好(需要创建一堆类,不好管理)

【思路二】

使用工厂方法模式

在这里插入图片描述

介绍

  • 工厂方法模式设计方案:将披萨项目的实例化功能抽象成抽象方法,在不同的口味点餐子类中具体实现。
  • 工厂方法模式:定义了一个创建对象的抽象方法,由子类决定要实例化的类。工厂方法模式将对象的实例化推迟到子类

实现

Pizza实现

【实体类】

package com.atguigu.factory.factorymethod.pizzastore.pizza;

//将Pizza 类做成抽象
public abstract class Pizza {
    protected String name; //名字

    //准备原材料, 不同的披萨不一样,因此,我们做成抽象方法
    public abstract void prepare();


    public void bake() {
        System.out.println(name + " baking;");
    }

    public void cut() {
        System.out.println(name + " cutting;");
    }

    //打包
    public void box() {
        System.out.println(name + " boxing;");
    }

    public void setName(String name) {
        this.name = name;
    }
}
package com.atguigu.factory.factorymethod.pizzastore.pizza;

public class BJCheesePizza extends Pizza {
    @Override
    public void prepare() {
        setName("北京的奶酪pizza");
        System.out.println(" 北京的奶酪pizza 准备原材料");
    }
}
package com.atguigu.factory.factorymethod.pizzastore.pizza;

public class BJPepperPizza extends Pizza {
   @Override
   public void prepare() {
      setName("北京的胡椒pizza");
      System.out.println(" 北京的胡椒pizza 准备原材料");
   }
}
package com.atguigu.factory.factorymethod.pizzastore.pizza;

public class LDCheesePizza extends Pizza{
   @Override
   public void prepare() {
      // TODO Auto-generated method stub
      setName("伦敦的奶酪pizza");
      System.out.println(" 伦敦的奶酪pizza 准备原材料");
   }
}
package com.atguigu.factory.factorymethod.pizzastore.pizza;

public class LDPepperPizza extends Pizza{
   @Override
   public void prepare() {
      // TODO Auto-generated method stub
      setName("伦敦的胡椒pizza");
      System.out.println(" 伦敦的胡椒pizza 准备原材料");
   }
}

【工厂类】

package com.atguigu.factory.factorymethod.pizzastore.order;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;

import com.atguigu.factory.factorymethod.pizzastore.pizza.Pizza;

/**
 * 抽象类
 */
public abstract class OrderPizza {

   /**
    * 定义一个抽象方法,createPizza , 让各个工厂子类自己实现
    * @param orderType
    * @return
    */
   abstract Pizza createPizza(String orderType);

   /**
    * 构造器
    */
   public OrderPizza() {
      Pizza pizza = null;
      // 订购披萨的类型
      String orderType;
      do {
         orderType = getType();
         //直接调用抽象方法,由工厂子类完成
         pizza = createPizza(orderType);
         //输出pizza 制作过程
         pizza.prepare();
         pizza.bake();
         pizza.cut();
         pizza.box();
         
      } while (true);
   }

   /**
    * 写一个方法,可以获取客户希望订购的披萨种类
    * @return
    */
   private String getType() {
      try {
         BufferedReader strin = new BufferedReader(new InputStreamReader(System.in));
         System.out.println("input pizza 种类:");
         String str = strin.readLine();
         return str;
      } catch (IOException e) {
         e.printStackTrace();
         return "";
      }
   }

}
package com.atguigu.factory.factorymethod.pizzastore.order;

import com.atguigu.factory.factorymethod.pizzastore.pizza.BJCheesePizza;
import com.atguigu.factory.factorymethod.pizzastore.pizza.BJPepperPizza;
import com.atguigu.factory.factorymethod.pizzastore.pizza.LDCheesePizza;
import com.atguigu.factory.factorymethod.pizzastore.pizza.LDPepperPizza;
import com.atguigu.factory.factorymethod.pizzastore.pizza.Pizza;

/**
 * 工厂子类:伦敦工厂
 */
public class LDOrderPizza extends OrderPizza {

   @Override
   Pizza createPizza(String orderType) {
   
      Pizza pizza = null;
      if(orderType.equals("cheese")) {
         pizza = new LDCheesePizza();
      } else if (orderType.equals("pepper")) {
         pizza = new LDPepperPizza();
      }
      return pizza;
   }

}
package com.atguigu.factory.factorymethod.pizzastore.order;

import com.atguigu.factory.factorymethod.pizzastore.pizza.BJCheesePizza;
import com.atguigu.factory.factorymethod.pizzastore.pizza.BJPepperPizza;
import com.atguigu.factory.factorymethod.pizzastore.pizza.Pizza;

/**
 * 工厂子类:北京工厂
 */
public class BJOrderPizza extends OrderPizza {

    @Override
    Pizza createPizza(String orderType) {
        Pizza pizza = null;
        if (orderType.equals("cheese")) {
            pizza = new BJCheesePizza();
        } else if (orderType.equals("pepper")) {
            pizza = new BJPepperPizza();
        }
        return pizza;
    }

}

【主类】

package com.atguigu.factory.factorymethod.pizzastore.order;

public class PizzaStore {

   public static void main(String[] args) {
      String loc = "bj";
      if (loc.equals("bj")) {
         //创建北京口味的各种Pizza
         new BJOrderPizza();
      } else {
         //创建伦敦口味的各种Pizza
         new LDOrderPizza();
      }
      // TODO Auto-generated method stub
   }

}

【运行】

input pizza 种类:
cheese
 北京的奶酪pizza 准备原材料
北京的奶酪pizza baking;
北京的奶酪pizza cutting;
北京的奶酪pizza boxing;
input pizza 种类:
pepper
 北京的胡椒pizza 准备原材料
北京的胡椒pizza baking;
北京的胡椒pizza cutting;
北京的胡椒pizza boxing;
input pizza 种类:
身份证创建

【需求】

输入人的姓名,创建身份证,并提供使用功能

【框架代码】

package com.atguigu.factory.factorymethod.Sample.framework;

public abstract class Product {
    public abstract void use();
}
package com.atguigu.factory.factorymethod.Sample.framework;

public abstract class Factory {

    public abstract Product createProduct(String owner);

}

【子类代码】

package com.atguigu.factory.factorymethod.Sample.idcard;


import com.atguigu.factory.factorymethod.Sample.framework.Product;

public class IDCard extends Product {
    private String owner;

    IDCard(String owner) {
        System.out.println("制作" + owner + "的ID卡。");
        this.owner = owner;
    }

    public void use() {
        System.out.println("使用" + owner + "的ID卡。");
    }

    public String getOwner() {
        return owner;
    }
}
package com.atguigu.factory.factorymethod.Sample.idcard;

import com.atguigu.factory.factorymethod.Sample.framework.*;

public class IDCardFactory extends Factory {

    public Product createProduct(String owner) {
        return new IDCard(owner);
    }

}

【主类】

package com.atguigu.factory.factorymethod.Sample;


import com.atguigu.factory.factorymethod.Sample.framework.*;
import com.atguigu.factory.factorymethod.Sample.idcard.*;

public class Main {
    public static void main(String[] args) {
        Factory factory = new IDCardFactory();
        Product card1 = factory.createProduct("小明");
        Product card2 = factory.createProduct("小红");
        Product card3 = factory.createProduct("小刚");
        card1.use();
        card2.use();
        card3.use();
    }
}

【运行】

制作小明的ID卡。
制作小红的ID卡。
制作小刚的ID卡。
使用小明的ID卡。
使用小红的ID卡。
使用小刚的ID卡。

【类图】

在这里插入图片描述

【登场角色】

  • Product(产品)
  • Creator(创建者):负责生成 Product角色的抽象类,Creator角色对于实际负责生成实例的ConcreteCreator角色一无所知它唯一知道的就是,只要调用生成实例的方法(如上图4的factoryMethod方法)就可以生成Product的实例
  • ConcreteProduct(具体的产品):决定具体的产品是什么,有什么用途
  • ConcreteCreator(具体的创建者):生成具体的产品

【分析】

现在是生成身份证,如果要生成其他产品,只需要修改ConcreteProduct和ConcreteCreator即可,框架不用改变

【衍生问题】

在这里插入图片描述

在这里插入图片描述

package com.atguigu.factory.factorymethod.A2.idcard;


import com.atguigu.factory.factorymethod.A2.framework.Product;

public class IDCard extends Product {
    private String owner;
    private int serial;
    IDCard(String owner, int serial) {
        System.out.println("制作" + owner + "(" + serial + ")" + "的ID卡。");
        this.owner = owner;
        this.serial = serial;
    }
    public void use() {
        System.out.println("使用" + owner + "(" + serial + ")" + "的ID卡。");
    }
    public int getSerial() {
        return serial;
    }
}
package com.atguigu.factory.factorymethod.A2.idcard;



import com.atguigu.factory.factorymethod.A2.framework.*;

import java.util.HashMap;

public class IDCardFactory extends Factory {
    private HashMap database = new HashMap();
    private int serial = 100;
    protected synchronized Product createProduct(String owner) {
        return new IDCard(owner, serial++);
    }
    public HashMap getDatabase() {
        return database;
    }
}

抽象工厂模式(尚硅谷版本)

介绍

  • 抽象工厂模式:定义了一个interface用于创建相关或有依赖关系的对象簇,而无需指明具体的类
  • 抽象工厂模式可以将简单工厂模式和工厂方法模式进行整合
  • 从设计层面看,抽象工厂模式就是对简单工厂模式的改进(或者称为进一步的抽象)
  • 将工厂抽象成两层,AbsFactory(抽象工厂) 和 具体实现的工厂子类。程序员可以根据创建对象类型使用对应的工厂子类。这样将单个的简单工厂类变成了工厂簇更利于代码的维护和扩展

在这里插入图片描述

实现

【抽象工厂接口】

package com.atguigu.factory.absfactory.pizzastore.order;

import com.atguigu.factory.absfactory.pizzastore.pizza.Pizza;

/**
 * 一个抽象工厂模式的抽象层(接口)
 */
public interface AbsFactory {

   /**
    * 让下面的工厂子类来 具体实现
    * @param orderType
    * @return
    */
   public Pizza createPizza(String orderType);
}

【工厂子类】

package com.atguigu.factory.absfactory.pizzastore.order;

import com.atguigu.factory.absfactory.pizzastore.pizza.BJCheesePizza;
import com.atguigu.factory.absfactory.pizzastore.pizza.BJPepperPizza;
import com.atguigu.factory.absfactory.pizzastore.pizza.Pizza;

//这是工厂子类
public class BJFactory implements AbsFactory {

   @Override
   public Pizza createPizza(String orderType) {
      System.out.println("~使用的是抽象工厂模式~");
      Pizza pizza = null;
      if(orderType.equals("cheese")) {
         pizza = new BJCheesePizza();
      } else if (orderType.equals("pepper")){
         pizza = new BJPepperPizza();
      }
      return pizza;
   }

}
package com.atguigu.factory.absfactory.pizzastore.order;


import com.atguigu.factory.absfactory.pizzastore.pizza.LDCheesePizza;
import com.atguigu.factory.absfactory.pizzastore.pizza.LDPepperPizza;
import com.atguigu.factory.absfactory.pizzastore.pizza.Pizza;


public class LDFactory implements AbsFactory {

   @Override
   public Pizza createPizza(String orderType) {
      Pizza pizza = null;
      if (orderType.equals("cheese")) {
         pizza = new LDCheesePizza();
      } else if (orderType.equals("pepper")) {
         pizza = new LDPepperPizza();
      }
      return pizza;
   }

}

【订购】

package com.atguigu.factory.absfactory.pizzastore.order;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;

import com.atguigu.factory.absfactory.pizzastore.pizza.Pizza;

public class OrderPizza {

   AbsFactory factory;

   // 构造器
   public OrderPizza(AbsFactory factory) {
      setFactory(factory);
   }

   private void setFactory(AbsFactory factory) {
      Pizza pizza = null;
      String orderType = "";
      this.factory = factory;
      do {
         // 用户输入
         orderType = getType();
         // factory 可能是北京的工厂子类,也可能是伦敦的工厂子类
         pizza = factory.createPizza(orderType);
         if (pizza != null) {
            //--if--订购ok
            pizza.prepare();
            pizza.bake();
            pizza.cut();
            pizza.box();
         } else {
            System.out.println("订购失败");
            break;
         }
      } while (true);
   }

   /**
    * 写一个方法,可以获取客户希望订购的披萨种类
    * @return
    */
   private String getType() {
      try {
         BufferedReader strin = new BufferedReader(new InputStreamReader(System.in));
         System.out.println("input pizza 种类:");
         String str = strin.readLine();
         return str;
      } catch (IOException e) {
         e.printStackTrace();
         return "";
      }
   }
}

【主类】

package com.atguigu.factory.absfactory.pizzastore.order;

public class PizzaStore {

   public static void main(String[] args) {
      //new OrderPizza(new BJFactory());
      new OrderPizza(new LDFactory());
   }

}

抽象工厂模式(《图解设计模式》)

介绍

  • 抽象工厂将抽象零件组装成为抽象产品,只关心接口,不关心零件的具体实现
  • 有多个具体工厂才适合使用抽象工厂模式

案例实现

在这里插入图片描述

【抽象类】

package com.atguigu.factory.absfactory.Sample.factory;

/**
 * 抽象工厂
 */
public abstract class Factory {
    /**
     * 根据指定的类名生成具体工厂的实例
     * @param classname
     * @return
     */
    public static Factory getFactory(String classname) {
        Factory factory = null;
        try {
            //Class.forName动态获取类信息
            //使用newInstance()生成类的实例
            //new的是具体工厂,后面转成抽象工厂
            factory = (Factory)Class.forName(classname).newInstance();
        } catch (ClassNotFoundException e) {
            System.err.println("没有找到 " + classname + "类。");
        } catch (Exception e) {
            e.printStackTrace();
        }
        return factory;
    }
    /**
     * 生成零件
     * @param caption
     * @return
     */
    public abstract Link createLink(String caption, String url);

    /**
     * 生成零件
     * @param caption
     * @return
     */
    public abstract Tray createTray(String caption);

    /**
     * 生成产品
     * @param title
     * @param author
     * @return
     */
    public abstract Page createPage(String title, String author);
}
package com.atguigu.factory.absfactory.Sample.factory;

/**
 * 项目:Link类和Tray类的父类
 */
public abstract class Item {
    /**
     * 项目标题
     */
    protected String caption;
    public Item(String caption) {
        this.caption = caption;
    }

    /**
     * 返回HTML文件的内容
     * @return
     */
    public abstract String makeHTML();
}
package com.atguigu.factory.absfactory.Sample.factory;

/**
 * 表示HTML的超链接
 * 因为Link没有实现Item的抽象方法,因此,Link也是抽象类
 */
public abstract class Link extends Item {
    protected String url;
    public Link(String caption, String url) {
        super(caption);
        this.url = url;
    }
}
package com.atguigu.factory.absfactory.Sample.factory;

import java.io.FileWriter;
import java.io.IOException;
import java.io.Writer;
import java.util.ArrayList;

/**
 * 抽象表示HTML页面(Link和Tray可以理解为抽象零件,Page可以理解为抽象产品)
 */
public abstract class Page {
    /**
     * 页面标题
     */
    protected String title;
    /**
     * 页面字段
     */
    protected String author;
    protected ArrayList content = new ArrayList();
    public Page(String title, String author) {
        this.title = title;
        this.author = author;
    }
    public void add(Item item) {
        content.add(item);
    }

    /**
     * 1、根据页面标题确认文件名
     * 2、调用makeHTML方法将自身保存的HTML内容写入到文件中
     */
    public void output() {
        try {
            String filename = title + ".html";
            Writer writer = new FileWriter(filename);
            writer.write(this.makeHTML());
            writer.close();
            System.out.println(filename + " 编写完成。");
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    public abstract String makeHTML();
}
package com.atguigu.factory.absfactory.Sample.factory;
import java.util.ArrayList;

/**
 * 托盘类
 * 里面可以包含多个Link和多个Tray,可以理解为上面放置了很多项目
 * 没有实现父类的抽象方法,该类也是抽象类
 */
public abstract class Tray extends Item {
    protected ArrayList tray = new ArrayList();
    public Tray(String caption) {
        super(caption);
    }

    /**
     * 添加项目
     * @param item
     */
    public void add(Item item) {
        tray.add(item);
    }
}

【具体工厂一:创建列表形式的页面】

package com.atguigu.factory.absfactory.Sample.listfactory;

import com.atguigu.factory.absfactory.Sample.factory.*;

/**
 * 具体工厂
 */
public class ListFactory extends Factory {
    public Link createLink(String caption, String url) {
        return new ListLink(caption, url);
    }

    public Tray createTray(String caption) {
        return new ListTray(caption);
    }

    public Page createPage(String title, String author) {
        return new ListPage(title, author);
    }
}
package com.atguigu.factory.absfactory.Sample.listfactory;

import com.atguigu.factory.absfactory.Sample.factory.*;

public class ListLink extends Link {
    public ListLink(String caption, String url) {
        super(caption, url);
    }

    public String makeHTML() {
        return "  <li><a href=\"" + url + "\">" + caption + "</a></li>\n";
    }
}
package com.atguigu.factory.absfactory.Sample.listfactory;

import com.atguigu.factory.absfactory.Sample.factory.*;

import java.util.Iterator;

public class ListPage extends Page {
    public ListPage(String title, String author) {
        super(title, author);
    }

    public String makeHTML() {
        StringBuffer buffer = new StringBuffer();
        buffer.append("<html><head><title>" + title + "</title></head>\n");
        buffer.append("<body>\n");
        buffer.append("<h1>" + title + "</h1>\n");
        buffer.append("<ul>\n");
        Iterator it = content.iterator();
        while (it.hasNext()) {
            Item item = (Item) it.next();
            buffer.append(item.makeHTML());
        }
        buffer.append("</ul>\n");
        buffer.append("<hr><address>" + author + "</address>");
        buffer.append("</body></html>\n");
        return buffer.toString();
    }
}
package com.atguigu.factory.absfactory.Sample.listfactory;

import com.atguigu.factory.absfactory.Sample.factory.*;

import java.util.Iterator;

public class ListTray extends Tray {
    public ListTray(String caption) {
        super(caption);
    }

    public String makeHTML() {
        StringBuffer buffer = new StringBuffer();
        buffer.append("<li>\n");
        buffer.append(caption + "\n");
        buffer.append("<ul>\n");
        Iterator it = tray.iterator();
        while (it.hasNext()) {
            Item item = (Item) it.next();
            buffer.append(item.makeHTML());
        }
        buffer.append("</ul>\n");
        buffer.append("</li>\n");
        return buffer.toString();
    }
}

【具体工厂二:创建表格形式的页面】

package com.atguigu.factory.absfactory.Sample.tablefactory;
import com.atguigu.factory.absfactory.Sample.factory.*;

/**
 * 多个具体工厂
 */
public class TableFactory extends Factory {
    public Link createLink(String caption, String url) {
        return new TableLink(caption, url);
    }
    public Tray createTray(String caption) {
        return new TableTray(caption);
    }
    public Page createPage(String title, String author) {
        return new TablePage(title, author);
    }
}
package com.atguigu.factory.absfactory.Sample.tablefactory;
import com.atguigu.factory.absfactory.Sample.factory.*;

public class TableLink extends Link {
    public TableLink(String caption, String url) {
        super(caption, url);
    }
    public String makeHTML() {
        return "<td><a href=\"" + url + "\">" + caption + "</a></td>\n";
    }
}
package com.atguigu.factory.absfactory.Sample.tablefactory;

import com.atguigu.factory.absfactory.Sample.factory.*;

import java.util.Iterator;

public class TablePage extends Page {
    public TablePage(String title, String author) {
        super(title, author);
    }
    public String makeHTML() {
        StringBuffer buffer = new StringBuffer();
        buffer.append("<html><head><title>" + title + "</title></head>\n");
        buffer.append("<body>\n");
        buffer.append("<h1>" + title + "</h1>\n");
        buffer.append("<table width=\"80%\" border=\"3\">\n");
        Iterator it = content.iterator();
        while (it.hasNext()) {
            Item item = (Item)it.next();
            buffer.append("<tr>" + item.makeHTML() + "</tr>");
        }
        buffer.append("</table>\n");
        buffer.append("<hr><address>" + author + "</address>");
        buffer.append("</body></html>\n");
        return buffer.toString();
    }
}
package com.atguigu.factory.absfactory.Sample.tablefactory;

import com.atguigu.factory.absfactory.Sample.factory.*;

import java.util.Iterator;

public class TableTray extends Tray {
    public TableTray(String caption) {
        super(caption);                     // 使用super(...)表达式  
    }

    public String makeHTML() {
        StringBuffer buffer = new StringBuffer();
        buffer.append("<td>");
        buffer.append("<table width=\"100%\" border=\"1\"><tr>");
        buffer.append("<td bgcolor=\"#cccccc\" align=\"center\" colspan=\"" + tray.size() + "\"><b>" + caption + "</b></td>");
        buffer.append("</tr>\n");
        buffer.append("<tr>\n");
        Iterator it = tray.iterator();
        while (it.hasNext()) {
            Item item = (Item) it.next();
            buffer.append(item.makeHTML());
        }
        buffer.append("</tr></table>");
        buffer.append("</td>");
        return buffer.toString();
    }
}

【委托加工】

package com.atguigu.factory.absfactory.Sample;


import com.atguigu.factory.absfactory.Sample.factory.*;

/**
 * 使用工厂将零件组装成为产品
 * 该类没有使用任何具体零件、产品、工厂,只使用抽象的
 */
public class Main {

    public static void main(String[] args) {
        String arg = "com.atguigu.factory.absfactory.Sample.listfactory.ListFactory";
        
        //创建工厂
        Factory factory = Factory.getFactory(arg);

        //创建零件
        Link people = factory.createLink("人民日报", "http://www.people.com.cn/");
        Link gmw = factory.createLink("光明日报", "http://www.gmw.cn/");

        Link us_yahoo = factory.createLink("Yahoo!", "http://www.yahoo.com/");
        Link jp_yahoo = factory.createLink("Yahoo!Japan", "http://www.yahoo.co.jp/");
        Link excite = factory.createLink("Excite", "http://www.excite.com/");
        Link google = factory.createLink("Google", "http://www.google.com/");

        Tray traynews = factory.createTray("日报");
        traynews.add(people);
        traynews.add(gmw);

        Tray trayyahoo = factory.createTray("Yahoo!");
        trayyahoo.add(us_yahoo);
        trayyahoo.add(jp_yahoo);

        Tray traysearch = factory.createTray("检索引擎");
        traysearch.add(trayyahoo);
        traysearch.add(excite);
        traysearch.add(google);

        //组装产品
        Page page = factory.createPage("LinkPage", "杨文轩");
        page.add(traynews);
        page.add(traysearch);
        page.output();
    }
}

【运行】

LinkPage.html 编写完成。

Process finished with exit code 0

生成的文件(列表形式)

<html><head><title>LinkPage</title></head>
<body>
<h1>LinkPage</h1>
<ul>
<li>
日报
<ul>
  <li><a href="http://www.people.com.cn/">人民日报</a></li>
  <li><a href="http://www.gmw.cn/">光明日报</a></li>
</ul>
</li>
<li>
检索引擎
<ul>
<li>
Yahoo!
<ul>
  <li><a href="http://www.yahoo.com/">Yahoo!</a></li>
  <li><a href="http://www.yahoo.co.jp/">Yahoo!Japan</a></li>
</ul>
</li>
  <li><a href="http://www.excite.com/">Excite</a></li>
  <li><a href="http://www.google.com/">Google</a></li>
</ul>
</li>
</ul>
<hr><address>杨文轩</address></body></html>

在这里插入图片描述

生成的文件(表格形式)

<html><head><title>LinkPage</title></head>
<body>
<h1>LinkPage</h1>
<table width="80%" border="3">
<tr><td><table width="100%" border="1"><tr><td bgcolor="#cccccc" align="center" colspan="2"><b>日报</b></td></tr>
<tr>
<td><a href="http://www.people.com.cn/">人民日报</a></td>
<td><a href="http://www.gmw.cn/">光明日报</a></td>
</tr></table></td></tr><tr><td><table width="100%" border="1"><tr><td bgcolor="#cccccc" align="center" colspan="3"><b>检索引擎</b></td></tr>
<tr>
<td><table width="100%" border="1"><tr><td bgcolor="#cccccc" align="center" colspan="2"><b>Yahoo!</b></td></tr>
<tr>
<td><a href="http://www.yahoo.com/">Yahoo!</a></td>
<td><a href="http://www.yahoo.co.jp/">Yahoo!Japan</a></td>
</tr></table></td><td><a href="http://www.excite.com/">Excite</a></td>
<td><a href="http://www.google.com/">Google</a></td>
</tr></table></td></tr></table>
<hr><address>杨文轩</address></body></html>

在这里插入图片描述

角色

  • AbstractProduct(抽象产品):负责定义抽象零件和产品的接口(API),如上面的Link、Tray、Page类
  • AbstractFactory(抽象工厂):负责定义生成抽象产品的接口(API),如上面的Factory类
  • Client(委托者):委托工厂加工产品,调用AbstractFactory 角色和AbstractProduct角色的接(API),如上面的Main类
  • ConcreteProduct(具体产品):负责实现AbstractProduct角色的接口,如上面的ListLink类、ListTray类和ListPage类;TableLink类、TableTray类和TablePage类
  • ConcreteFactory( 具体工厂):负责实现AbstractFactory角色的接口,如上面的Listfactory类、Tablefactory类

在这里插入图片描述

分析

  • 容易增加具体工厂:只需要编写Factory、LinkTray、Page这4个类的子类,实现抽象方法
  • 难以增加新零件:如在factory包中增加一个表示图像的Picture零件,需要在抽象工厂中增加一个createPicture的方法,所有的具体工厂都需要新增代码,具体工厂越多,工作量越大

简单工厂模式在JDK中的应用

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

小结

  • 工厂模式的意义:将实例化对象的代码提取出来,放到一个类中统一管理和维护,达到和主项目的依赖关系的解耦,从而提高项目的扩展和维护性
  • 工厂模式有三种

工厂模式体现依赖抽象原则的点:

  • 创建对象实例时,不要直接 new 类,而是把这个new 类的动作放在一个工厂的方法中,并返回。有的书上说,变量不要直接持有具体类的引用,应该引用抽象类
  • 不要让类继承具体类,而是继承抽象类或者是实现interface(接口)
  • 不要覆盖基类中已经实现的方法

文章说明

本文章为本人学习尚硅谷的学习笔记,文章中大部分内容来源于尚硅谷视频(点击学习尚硅谷相关课程),也有部分内容来自于自己的思考,发布文章是想帮助其他学习的人更方便地整理自己的笔记或者直接通过文章学习相关知识,如有侵权请联系删除,最后对尚硅谷的优质课程表示感谢。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/750170.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Hive SQL 迁移 Flink SQL 在快手的实践

摘要&#xff1a;本文整理自快手数据架构工程师张芒&#xff0c;阿里云工程师刘大龙&#xff0c;在 Flink Forward Asia 2022 生产实践专场的分享。本篇内容主要分为四个部分&#xff1a; Flink 流批一体引擎 Flink Batch 生产实践 核心优化解读 未来规划 点击查看原文视频…

切换.net Framework 版本后,出现NuGet 包是使用不同于当前目标框架的目标框架安装的,可能需要重新安装

问题现象&#xff1a; 由于添加新的dll文件&#xff0c;依赖的.NET Framework版本与当前的不一致&#xff0c;在vs 中切换了目标框架版本后&#xff0c;运行程序&#xff0c;出现以下的warnning信息&#xff1a; 一些 NuGet 包是使用不同于当前目标框架的目标框架安装的&#…

springboot社区疫情防控平台

开发语言&#xff1a;Java 框架&#xff1a;springboot JDK版本&#xff1a;JDK1.8 服务器&#xff1a;tomcat7 数据库&#xff1a;mysql 5.7&#xff08;一定要5.7版本&#xff09; 数据库工具&#xff1a;Navicat11 开发软件&#xff1a;eclipse/myeclipse/idea Maven…

剑指offer68-I.二叉搜索树的最近公共祖先

把p的所有祖先找出来&#xff0c;把q的所有祖先找出来&#xff0c;因为是是搜索树&#xff0c;找出来的祖先都是排好序的&#xff0c;所以可以把找出来的祖先从后面往前面遍历&#xff0c;第一个相同的值的数就是最近的公共祖先&#xff0c;这是我一开始的想法,但是它最后报错了…

(六)人工智能应用--深度学习原理与实战--理解张量与运算图

Tensorflow名称中的Tensor即张量&#xff0c;不仅仅是Tensorflow&#xff0c;几乎所有的深度学习平台都以张量为基本的数据结构。简单来说&#xff0c;张量就是多维数组&#xff0c;本质上是一种数据容器&#xff0c;它可以有任意维度&#xff0c;比如矩阵就是二维张量(二维数组…

数字图像处理【11】OpenCV-Canny边缘提取到FindContours轮廓发现

本章主要介绍图像处理中一个比较基础的操作&#xff1a;Canny边缘发现、轮廓发现 和 绘制轮廓。概念不难&#xff0c;主要是结合OpenCV 4.5的API相关操作&#xff0c;为往下 "基于距离变换的分水岭图像分割" 做知识储备。 Canny边缘检测 在讲述轮廓之前&#xff0c;…

数字孪生,建设智慧城市的新型“加速器”

城市是什么&#xff1f; 是现代文明与生态的联结&#xff0c;是自然与人友好栖息的空间&#xff0c;是运转复杂庞大的系统。 今天&#xff0c;中国的城市在历经十余年的“智慧城市”建设后已经被赋予了数智融合的全新解读。随着近年来5G、云计算、人工智能爆发式能量增长&#…

常见的bug---4、在DataGrip上跑本地模式报return 2异常

文章目录 问题描述原因分析&#xff1a;解决方案&#xff1a; 问题描述 FAILED: Execution Error, return code 2 from org.apache.hadoop.hive.ql.exec.mr.MapRedTask 在DataGrip上设置了Hive的本地模式。虽然可以建表、但是无法对表进行插入数据 原因分析&#xff1a; 在插…

深入理解张量维度的真正含义

在人工智能领域&#xff0c;比如深度学习&#xff0c;机器学习&#xff0c;张量这一概念被频繁使用。虽然网上有很多关于张量的文章&#xff0c;但基本都是废话太多&#xff0c;而且复制粘贴说不到重点。 今天我就来讲解一下张量维度的真正含义。 首先. 张量并不是一个简单多…

STM32F103驱动VL53L0X激光测距模块

STM32F103驱动VL53L0X激光测距模块 简介引脚定义STM32F103ZET6开发板与VL53L0X模块接线测试代码实验结果 简介 TOF 是飞行时间&#xff08;Tlme of Flight&#xff09;技术的缩写&#xff0c;即传感器发出经过调制的近红外光&#xff0c;遇到物体后反射&#xff0c;传感器通过…

bug:file name too long文件名超出系统最大限制

各操作系统支持最长的文件和目录名称长度&#xff08;Linux、Win、Mac&#xff09; 今天开发需求的时候发现无法新建文件&#xff0c;提示file name too lang&#xff0c;于是翻阅和查询了一些资料&#xff0c;发现不同操作系统下文件名和目录名最长的长度不同。 操作系统文件名…

游戏如何应对虚拟定位问题

在游戏系统设计中&#xff0c;排行榜这一设计可谓是十分巧妙。它可以充分调动玩家的“胜负欲”&#xff0c;给予玩家前进的目标及动力&#xff0c;满足玩家的心理需求。 排行榜的设计使用范围广&#xff0c;对游戏留存、付费等指标提升效果出众&#xff0c;在不少游戏中都可以…

玩机搞机---某些安卓定制机解除系统安装限制的思路与分析过程

定制机的意义不多做解释&#xff0c;懂的人都明白. 在一些定制机中会限制用户安装app。当你使用第三方工具或者adb指令安卓app是他会提示de xxx.apk. autostarter is not auth,install failed!等等类似的提示&#xff0c;在解决某些定制系统中类似问题的过程中&#xff0c;基本…

Unity知识记录--项目升级URP

URP是指Unity的通用渲染管线&#xff0c;此处主要针对原有项目进行升级使用&#xff0c;但并不是所有的内容都可以直接通过升级完成&#xff0c;直接使用的Unity默认的shader通常可以完成直接升级&#xff0c;自己编写的shader通常需要重做。 首先我们先要安装这个Package&…

汇报方案设计方案规划方案资源下载

标题汇报方案设计方案规划方案资源下载https://wheart.cn/so/home?mdw&tag%E5%AE%89%E5%85%A8文章标签事业单位人事人才信息综合管理系统建设设计报价方案人事系统,人事人才,事业单位,工资系统,职称系统xx纪检委智慧监督平台建设方案汇报.docx建设方案,规划设计,汇报方案营…

程序员如何走向世界!

&#x1f337;&#x1f341; 博主 libin9iOak带您 Go to New World.✨&#x1f341; &#x1f984; 个人主页——libin9iOak的博客&#x1f390; &#x1f433; 《面试题大全》 文章图文并茂&#x1f995;生动形象&#x1f996;简单易学&#xff01;欢迎大家来踩踩~&#x1f33…

训练速度提升300倍,Niantic最新VPS视觉定位方案亮相

近年来在谷歌、Niantic等推动下&#xff0c;视觉定位对于AR应用的重要性越来越明显&#xff0c;尤其是在室内导航场景&#xff0c;定位精度可超越传统GPS方案。为了进一步提升视觉定位、深度视觉地图构建的准确性&#xff0c;Niantic Labs在CVPR 2023期间公布了ACE方案&#xf…

[MySql]表的增删查改

目录 前言: 1.插入数据 2.查询数据 2.1全列查询 2.2指定查询 2.3别名 2.4去重 2.5排序 2.6条件查询 2.7聚合查询 2.7.1group by语句 2.7.2havin语句 2.8联合查询 2.8.1内连接 2.8.2外连接 2.8.3自连接 2.8.4子查询 3.修改 4.删除 前言: 本次大多数使用…