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

工厂模式

需求了解

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

  • 披萨的种类很多(比如 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披萨),我们需要做如下修改

在这里插入图片描述

改进
  • 修改代码可以接受,但是如果我们在其它的地方也有创建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(接口)
  • 不要覆盖基类中已经实现的方法

文章说明

  • 本文章为本人学习尚硅谷的学习笔记,文章中大部分内容来源于尚硅谷视频(点击学习尚硅谷相关课程),也有部分内容来自于自己的思考,发布文章是想帮助其他学习的人更方便地整理自己的笔记或者直接通过文章学习相关知识,如有侵权请联系删除,最后对尚硅谷的优质课程表示感谢。
  • 本人还同步阅读《图解设计模式》书籍(图解设计模式/(日)结城浩著;杨文轩译–北京:人民邮电出版社,2017.1),进而综合两者的内容,让知识点更加全面
  • 3
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
工厂模式是一种创建型设计模式,它提供了一个创建对象的最佳方式。在工厂模式中,我们创建对象而不必将创建过程暴露给客户端,并且客户端使用工厂方法来创建对象。 在 Java 中,我们可以通过接口或抽象类来定义工厂方法,然后使用具体的类来实现这个接口或抽象类。这样一来,我们就可以将具体的实现隐藏在工厂方法中,而客户端只需要使用工厂方法来创建对象。 例如,我们可以定义一个接口 ShapeFactory,然后使用具体的类 CircleFactory 和 RectangleFactory实现这个接口。客户端只需要使用 ShapeFactory 来创建 Circle 或 Rectangle 对象,而不需要知道具体的实现细节。 下面是一个简单的工厂模式的示例代码: ```java // 定义形状接口 interface Shape { void draw(); } // 定义圆形类 class Circle implements Shape { public void draw() { System.out.println("画一个圆形"); } } // 定义矩形类 class Rectangle implements Shape { public void draw() { System.out.println("画一个矩形"); } } // 定义工厂接口 interface ShapeFactory { Shape createShape(); } // 定义圆形工厂类 class CircleFactory implements ShapeFactory { public Shape createShape() { return new Circle(); } } // 定义矩形工厂类 class RectangleFactory implements ShapeFactory { public Shape createShape() { return new Rectangle(); } } // 客户端代码 public class FactoryPatternDemo { public static void main(String[] args) { // 创建圆形 ShapeFactory circleFactory = new CircleFactory(); Shape circle = circleFactory.createShape(); circle.draw(); // 创建矩形 ShapeFactory rectangleFactory = new RectangleFactory(); Shape rectangle = rectangleFactory.createShape(); rectangle.draw(); } } ``` 在这个示例中,我们定义了一个 Shape 接口和两个具体的形状类 Circle 和 Rectangle。然后我们定义了一个 ShapeFactory 接口和两个具体的工厂类 CircleFactory 和 RectangleFactory,用于创建 Circle 和 Rectangle 对象。最后,我们在客户端代码中使用这些工厂类来创建对象,并调用对象的 draw 方法来画出形状。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Hello Dam

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值