尚硅谷设计模式学习(4)---[简单工厂模式,工厂方法模式,抽象工厂模式]

本文通过披萨店案例,详细解析了简单工厂模式、工厂方法模式及抽象工厂模式的应用场景与实现方式,强调了开闭原则的重要性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

🚀🚀🚀尚硅谷传送门==>B站尚硅谷Java设计模式

❤❤❤感谢尚硅谷❤❤❤

🛴🛴🛴最近开始计划学习一下设计模式了,加油!!!



🚗简单工厂模式

从披萨店的案例引入工厂模式,进入学习

披萨的种类很多(比如 GreekPizza、CheesePizza 等)

  • 披萨的制作有 prepare(准备材料工作),bake(烘烤工作), cut(切片工作), box(包装工作)
  • 完成披萨店订购功能。

先分析传统思路

在这里插入图片描述

在这里插入图片描述

传统思路代码

披萨类Pizza

//将披萨类定义为抽象类;
public abstract class Pizza {
    //披萨的种类名;
    protected String name;

    //制作披萨时准备原材料的工作;
    public abstract void prepare();

    //烘烤披萨;
    public void bake() {
        System.out.println(name + " 烘焙中...;");
    }

    //披萨切片;
    public void cut() {
        System.out.println(name + " 切片中.....;");
    }

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

    //为披萨设置种类名;
    public void setName(String name) {
        this.name = name;
    }
}

奶酪披萨类CheesePizza

//奶酪披萨类;
public class CheesePizza extends Pizza{
    @Override
    public void prepare() {
        setName("奶酪披萨");
        System.out.println("奶酪披萨准备材料工作");
    }
}

希腊披萨类GreekPizza

public class GreekPizza extends Pizza{
    @Override
    public void prepare() {
        setName("希腊披萨");
        System.out.println("希腊披萨准备工作");
    }
}

订购披萨类ToOrderPizza

//订购披萨类;
public class ToOrderPizza {
    //初始化时执行构造方法;
    public ToOrderPizza() {
        Pizza pizza = null;
        //订购的种类;
        String orderType;
        do {
            //动态获取订购披萨的种类;
            orderType=gettype();
            if(orderType.equals("CheesePizza")){
                pizza=new CheesePizza();
            }else if(orderType.equals("GreekPizza")){
                pizza=new GreekPizza();
            }else {
                break;
            }
            //进行披萨的制作;
            pizza.prepare();
            pizza.bake();
            pizza.cut();
            pizza.box();
        } while (true);
    }

    //输入台获取披萨的种类;
    private String gettype() {
        try {
            BufferedReader strs = new BufferedReader(new InputStreamReader(System.in));
            System.out.println("输入订购的披萨种类:");
            String str = strs.readLine();
            return str;
        } catch (IOException e) {
            e.printStackTrace();
            return "";
        }
    }
}

披萨店PizzaShop

//披萨店类;
public class PizzaShop {
    public static void main(String[] args) {

        //订购披萨,完成工作;
        new ToOrderPizza();
    }
}

尝试使用;

输入订购的披萨种类:
CheesePizza
奶酪披萨准备材料工作
奶酪披萨 烘焙中...;
奶酪披萨 切片中.....;
奶酪披萨 打包....;
输入订购的披萨种类:
GreekPizza
希腊披萨准备工作
希腊披萨 烘焙中...;
希腊披萨 切片中.....;
希腊披萨 打包....;
输入订购的披萨种类:
qweqw

需要注意的是,如果需要增加另外的披萨种类时,就要去创建新的种类;然后在订购披萨时添加新的依赖;
这样的做法会导致依赖关系复杂;
违反了设计模式的OCP(开闭原则);[对扩展开放,对修改关闭]

在这里插入图片描述


引入简单工厂模式进行优化

简单工厂模式作为创建型模式,仅需要一个工厂对象去决定创建的是哪种披萨产品的实例对象即可.

引入一个简单工厂类将创建着各种个披萨实例对象进行封装;
所有的订购披萨类都在这个简单工厂类中创建对象;
保证了扩展新种类披萨后,只需要在简单工厂类中修改即可.

也去避免了在增加新的披萨种类后(即提供方扩展了新的功能/属性后;作为使用方的订购类完全不需要去考虑在自己的内部修改代码);保证了开闭原则.

在这里插入图片描述

增加一个简单工厂类SimpleFactory

//使用简单工厂将创建披萨对象封装起来;
public class SimpleFactory {
    //根据披萨的种类去提供披萨的对象实例;
    public Pizza createPizza(String orderType){
        Pizza pizza=null;
        if(orderType.equals("CheesePizza")){
            pizza=new CheesePizza();
        }else if(orderType.equals("GreekPizza")){
            pizza=new GreekPizza();
        }
        return pizza;
    }
}

修改订购披萨类ToOrderPizza

//订购披萨类;
public class ToOrderPizza {
    //定义简单工厂属性;
    private SimpleFactory simpleFactory;

    Pizza pizza=null;

    //在初始化构造方法处就去设置简单工厂对象;
    public ToOrderPizza(SimpleFactory simpleFactory) {
        setSimpleFactory(simpleFactory);
    }

    //设置简单工厂对象;
    public void setSimpleFactory(SimpleFactory simpleFactory) {
        //用户输入披萨类型;
        String orderType="";
        //设置简单工厂对象;
        this.simpleFactory = simpleFactory;
        do {
            //先获取披萨种类;
            orderType = gettype();
            //调用工厂对象的方法创建披萨对象;
            pizza = this.simpleFactory.createPizza(orderType);

            if(pizza!=null){
                //披萨制作;
                pizza.prepare();
                pizza.bake();
                pizza.cut();
                pizza.box();
            }else{
                System.out.println("<----没有该种类披萨,订购失败---->");
                break;
            }
        }while (true);
    }

    //获取披萨的种类;
    private String gettype() {
        try {
            BufferedReader strs = new BufferedReader(new InputStreamReader(System.in));
            System.out.println("输入订购的披萨种类:");
            String str = strs.readLine();
            return str;
        } catch (IOException e) {
            e.printStackTrace();
            return "";
        }
    }
}

披萨店类调用订购类时,构造方法内传入简单工厂对象;

//披萨店类;
public class PizzaShop {
    public static void main(String[] args) {
        //订购披萨;
        new ToOrderPizza(new SimpleFactory());
        System.out.println("结束");
    }
}

测试使用;

输入订购的披萨种类:
CheesePizza
奶酪披萨准备材料工作
奶酪披萨 烘焙中...;
奶酪披萨 切片中.....;
奶酪披萨 打包....;
输入订购的披萨种类:
GreekPizza
希腊披萨准备工作
希腊披萨 烘焙中...;
希腊披萨 切片中.....;
希腊披萨 打包....;
输入订购的披萨种类:
adsasdsa
<----没有该种类披萨,订购失败---->
结束

简单工厂模式,实际上也可以修改为静态工厂模式,
将简单工厂内的创建披萨对象方法设置为静态方法;
这样,在订购类中无需创建工厂对象即可调用方法;

简单静态工厂类;SimpleFactory

//使用简单工厂将创建披萨对象封装起来;
public class SimpleFactory {
    //根据披萨的种类去提供披萨的对象实例;
    public static Pizza createPizza(String orderType){
        Pizza pizza=null;
        if(orderType.equals("CheesePizza")){
            pizza=new CheesePizza();
        }else if(orderType.equals("GreekPizza")){
            pizza=new GreekPizza();
        }
        return pizza;
    }
}

订购披萨类ToOrderPizza;
自然也就不需要去定义工厂类作为属性了;直接调用方法即可.

//订购披萨类;
public class ToOrderPizza {

    Pizza pizza=null;
    //定义披萨类型;
    String orderType="";
    //在初始化构造方法;
    public ToOrderPizza() {
        do {
            //先获取披萨种类;
            orderType = gettype();
            //调用简单工厂的方法创建披萨对象;
            pizza = SimpleFactory.createPizza(orderType);
            if(pizza!=null){
                //披萨制作;
                pizza.prepare();
                pizza.bake();
                pizza.cut();
                pizza.box();
            }else{
                System.out.println("<----没有该种类披萨,订购失败---->");
                break;
            }
        }while (true);
    }

    //获取披萨的种类;
    private String gettype() {
        try {
            BufferedReader strs = new BufferedReader(new InputStreamReader(System.in));
            System.out.println("输入订购的披萨种类:");
            String str = strs.readLine();
            return str;
        } catch (IOException e) {
            e.printStackTrace();
            return "";
        }
    }
}

披萨店类PizzaShop

//披萨店类;
public class PizzaShop {
    public static void main(String[] args) {
        //订购披萨,完成工作;
        new ToOrderPizza();
        System.out.println("结束");
    }
}

🚗工厂方法模式

这时有一个新的需求,在点披萨的时候,还要考虑产地问题;

如果说,还用简单工厂模式解决的话,此时需要创建几个不同产地的简单工厂类(每个工厂类内部决定创建什么口味的披萨实例对象);
那么只要来个订购类;他就需要去聚合;项目的耦合过高,维护性差.

在这里插入图片描述

那么,引入工厂方法模式;让子类决定对象的实例化

而工厂方法模式是在工厂类中定义创建不同口味披萨对象的抽象方法;
然后让不同产地的子类继承这个工厂类;
不同产地的子类在实现方法时,依赖于不同口味的披萨对象.

在这里插入图片描述

在这里插入图片描述

案例代码;
披萨类Pizza

//将披萨类定义为抽象类;
public abstract class Pizza {
    //披萨的种类名;
    protected String name;

    //制作披萨时准备原材料的工作;
    public abstract void prepare();

    //烘烤披萨;
    public void bake() {
        System.out.println(name + " 烘焙中...;");
    }

    //披萨切片;
    public void cut() {
        System.out.println(name + " 切片中.....;");
    }

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

    //为披萨设置种类名;
    public void setName(String name) {
        this.name = name;
    }
}

北京生产的奶酪味披萨BJChessPizza

//北京生产的的奶酪味披萨
public class BJChessPizza extends Pizza{
    @Override
    public void prepare() {
        setName("北京奶酪味披萨");
        System.out.println("北京生产的奶酪味披萨准备工作==>;");
    }
}

北京生产的胡椒味披萨BJPepperPizza

//北京生产的胡椒味披萨;
public class BJPepperPizza extends Pizza{
    @Override
    public void prepare() {
        setName("北京胡椒味披萨");
        System.out.println("北京生产的胡椒味披萨准备工作==>;");
    }
}

伦敦生产的奶酪味披萨LDChessPizza

//伦敦生产的的奶酪味披萨
public class LDChessPizza extends Pizza{
    @Override
    public void prepare() {
        setName("伦敦奶酪味披萨");
        System.out.println("伦敦生产的奶酪味披萨准备工作==>;");
    }
}

伦敦生产的胡椒味披萨LDPepperPizza

//伦敦生产的胡椒味披萨;
public class LDPepperPizza extends Pizza{
    @Override
    public void prepare() {
        setName("伦敦胡椒味披萨");
        System.out.println("伦敦生产的胡椒味披萨准备工作==>;");
    }
}

订购披萨类ToOrderPizza

//订购披萨类;
public abstract class ToOrderPizza {
    
    //定义根据披萨种类创建披萨对象的抽象方法
    abstract Pizza createPizza(String orderType);

    //在初始化构造方法;
    public ToOrderPizza() {
        Pizza pizza = null;
        //定义披萨类型;
        String orderType = "";
        do {
            //先获取披萨种类;
            orderType = gettype();
            //这里的方法由子类去实现;
            pizza=createPizza(orderType);
            if(pizza!=null) {
                //披萨制作;
                pizza.prepare();
                pizza.bake();
                pizza.cut();
                pizza.box();
            }else{
                System.out.println("<----没有该种类披萨,订购失败---->");
                break;
            }
        } while (true);
    }

    //获取披萨的种类;
    private String gettype() {
        try {
            BufferedReader strs = new BufferedReader(new InputStreamReader(System.in));
            System.out.println("输入订购的披萨种类:");
            String str = strs.readLine();
            return str;
        } catch (IOException e) {
            e.printStackTrace();
            return "";
        }
    }
}

北京生产的订购披萨类BJOrderPizza

//北京产地的订购披萨;
public class BJOrderPizza extends ToOrderPizza{
    @Override
    Pizza createPizza(String orderType) {
        Pizza pizza=null;
        if(orderType.equals("chess")){
            pizza = new BJChessPizza();
        }else if(orderType.equals("pepper")){
            pizza = new BJPepperPizza();
        }
        return pizza;
    }
}

伦敦生产的订购披萨类LDOrderPizza

//伦敦产地的订购披萨;
public class LDOrderPizza extends ToOrderPizza{
    @Override
    Pizza createPizza(String orderType) {
        Pizza pizza=null;
        if(orderType.equals("chess")){
            pizza = new LDChessPizza();
        }else if(orderType.equals("pepper")){
            pizza = new LDPepperPizza();
        }
        return pizza;
    }
}

披萨店类PizzaShop

public class PizzaShop {
    public static void main(String[] args) {

        getPizza();
    }

    //选择产地;
    public static void getPizza(){
        PizzaShop pizzaShop=new PizzaShop();
        String gettype = pizzaShop.gettype();
        if(gettype.equals("北京")){
            new BJOrderPizza();
        }else if(gettype.equals("伦敦")){
            new LDOrderPizza();
        }else {
            System.out.println("抱歉,暂时不提供该产地");
        }
    }

    //输入选择生产地;
    private String gettype() {
        try {
            BufferedReader strs = new BufferedReader(new InputStreamReader(System.in));
            System.out.println("输入订购的披萨产地(目前仅提供北京/伦敦):");
            String str = strs.readLine();
            return str;
        } catch (IOException e) {
            e.printStackTrace();
            return "";
        }
    }
}

测试使用

输入订购的披萨产地(目前仅提供北京/伦敦):
伦敦
输入订购的披萨种类:
chess
伦敦生产的奶酪味披萨准备工作==>;
伦敦奶酪味披萨 烘焙中...;
伦敦奶酪味披萨 切片中.....;
伦敦奶酪味披萨 打包....;
输入订购的披萨种类:
pepper
伦敦生产的胡椒味披萨准备工作==>;
伦敦胡椒味披萨 烘焙中...;
伦敦胡椒味披萨 切片中.....;
伦敦胡椒味披萨 打包....;
输入订购的披萨种类:
adsad
<----没有该种类披萨,订购失败---->

🚗抽象工厂模式

抽象工厂模式:定义了一个 接口 用于创建相关或有依赖关系的对象簇,而无需指明具体的类

  • 抽象工厂模式将简单工厂模式和工厂方法模式进行整合。

需要注意的是;在上一种抽象方法的案例中;要是多几个订购类呢;
后果就是让 (北京订购披萨,伦敦订购披萨) 都再去继承新增的订购类吗?

在这里插入图片描述

那么,是不是要来一个接口去管理管理这些上面的订购类呢,然后让 ( 北京订购披萨类,伦敦订购披萨类)去实现这个接口;

俗话说的好,最好的解决方式就是 “加一层”

大概类图如下

在这里插入图片描述

在这里插入图片描述

案例代码

披萨类Pizza

//将披萨类定义为抽象类;
public abstract class Pizza {
    //披萨的种类名;
    protected String name;

    //制作披萨时准备原材料的工作;
    public abstract void prepare();

    //烘烤披萨;
    public void bake() {
        System.out.println(name + " 烘焙中...;");
    }

    //披萨切片;
    public void cut() {
        System.out.println(name + " 切片中.....;");
    }

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

    //为披萨设置种类名;
    public void setName(String name) {
        this.name = name;
    }
}

北京生产的奶酪味披萨BJChessPizza

//北京生产的的奶酪味披萨
public class BJChessPizza extends Pizza{
    @Override
    public void prepare() {
        setName("北京奶酪味披萨");
        System.out.println("北京生产的奶酪味披萨准备工作==>;");
    }
}

北京生产的胡椒味披萨BJPepperPizza

//北京生产的胡椒味披萨;
public class BJPepperPizza extends Pizza{
    @Override
    public void prepare() {
        setName("北京胡椒味披萨");
        System.out.println("北京生产的胡椒味披萨准备工作==>;");
    }
}

伦敦生产的奶酪味披萨LDChessPizza

//伦敦生产的的奶酪味披萨
public class LDChessPizza extends Pizza{
    @Override
    public void prepare() {
        setName("伦敦奶酪味披萨");
        System.out.println("伦敦生产的奶酪味披萨准备工作==>;");
    }
}

伦敦生产的胡椒味披萨LDPepperPizza

//伦敦生产的胡椒味披萨;
public class LDPepperPizza extends Pizza{
    @Override
    public void prepare() {
        setName("伦敦胡椒味披萨");
        System.out.println("伦敦生产的胡椒味披萨准备工作==>;");
    }
}

抽象层工厂接口AbstractFactory

//抽象工厂模式;抽象层
public interface AbstractFactory {

    //定义抽象方法; 根据口味类型 创建披萨实例对象;
    public  abstract Pizza createPizza(String orderType);
}

北京产地BJFactory

//北京产地;
public class BJFactory implements AbstractFactory{
    @Override
    public Pizza createPizza(String orderType) {
        Pizza pizza=null;
        if(orderType.equals("chess")){
            pizza = new BJChessPizza();
        }else if(orderType.equals("pepper")){
            pizza = new BJPepperPizza();
        }
        return pizza;
    }
}

伦敦产地LDFactory

//伦敦产地;
public class LDFactory implements AbstractFactory{
    @Override
    public Pizza createPizza(String orderType) {
        Pizza pizza=null;
        if(orderType.equals("chess")){
            pizza = new LDChessPizza();
        }else if(orderType.equals("pepper")){
            pizza = new LDPepperPizza();
        }
        return pizza;
    }
}

订购类ToOrderPizza

//订购披萨类;
public class ToOrderPizza {
    //抽象工厂聚合

    AbstractFactory abstractFactory;

    private void setAbstractFactory(AbstractFactory abstractFactory) {
        Pizza pizza=null;
        String orderType="";

        this.abstractFactory = abstractFactory;
        do {
            orderType=gettype();
            pizza=abstractFactory.createPizza(orderType);
            if(pizza!=null) {
                //披萨制作;
                pizza.prepare();
                pizza.bake();
                pizza.cut();
                pizza.box();
            }else{
                System.out.println("<----没有该种类披萨,订购失败---->");
                break;
            }
        }while (true);
    }


    //构造方法;
    public ToOrderPizza(AbstractFactory abstractFactory){
        setAbstractFactory(abstractFactory);
    }


    //获取披萨的种类;
    private String gettype() {
        try {
            BufferedReader strs = new BufferedReader(new InputStreamReader(System.in));
            System.out.println("输入订购的披萨种类:");
            String str = strs.readLine();
            return str;
        } catch (IOException e) {
            e.printStackTrace();
            return "";
        }
    }
}

披萨店类PizzaShop

public class PizzaShop {
    public static void main(String[] args) {

        getPizza();
    }

    //选择产地;
    public static void getPizza(){
        PizzaShop pizzaShop=new PizzaShop();
        String gettype = pizzaShop.gettype();
        if(gettype.equals("北京")){
            new ToOrderPizza(new BJFactory());
        }else if(gettype.equals("伦敦")){
            new ToOrderPizza(new LDFactory());
        }else {
            System.out.println("抱歉,暂时不提供该产地");
        }
    }

    //输入选择生产地;
    private String gettype() {
        try {
            BufferedReader strs = new BufferedReader(new InputStreamReader(System.in));
            System.out.println("输入订购的披萨产地(目前仅提供北京/伦敦):");
            String str = strs.readLine();
            return str;
        } catch (IOException e) {
            e.printStackTrace();
            return "";
        }
    }
}

测试

输入订购的披萨产地(目前仅提供北京/伦敦):
北京
输入订购的披萨种类:
chess
北京生产的奶酪味披萨准备工作==>;
北京奶酪味披萨 烘焙中...;
北京奶酪味披萨 切片中.....;
北京奶酪味披萨 打包....;
输入订购的披萨种类:
pepper
北京生产的胡椒味披萨准备工作==>;
北京胡椒味披萨 烘焙中...;
北京胡椒味披萨 切片中.....;
北京胡椒味披萨 打包....;
输入订购的披萨种类:
dasda
<----没有该种类披萨,订购失败---->

jdk中的工厂模式源码案例;

比如说日历类 Calendar就用到了简单工厂模式

在这里插入图片描述

在这里插入图片描述

  • 创建对象实例时,不要直接 new 类, 而是把这个new 类的动作放在一个工厂的方法中,并返回。
  • 不要让类继承具体类,而是继承抽象类或者是实现 接口
  • 不要重写基类中已实现的方法。

共150讲,时长共 33小时18分钟 1) 优秀的程序应该是这样的:阅读时,感觉很优雅;新增功能时,感觉很轻松;运行时,感觉很快速,这就需要设计模式支撑。 2) 设计模式包含了大量的编程思想,讲授和真正掌握并不容易,网上的设计模式课程不少,大多讲解的比较晦涩,没有真实的应用场景和框架源码支撑,学习后,只知其形,不知其神。就会造成这样结果: 知道各种设计模式,但是不知道怎么使用到真实项目。本课程针对上述问题,有针对性的进行了升级 (1) 授课方式采用 图解+框架源码分析的方式,让课程生动有趣好理解 (2) 系统全面的讲解了设计模式,包括 设计模式七大原则、UML类图-类的六大关系、23种设计模式及其分类,比如 单例模式的8种实现方式、工厂模式的3种实现方式、适配器模式的3种实现、代理模式的3种方式、深拷贝等 3) 如果你想写出规范、漂亮的程序,就花时间来学习设计模式吧 课程内容和目标 本课程是使用Java来讲解设计模式,考虑到设计模式比较抽象,授课采用 图解+框架源码分析的方式 1) 内容包括: 设计模式七大原则(单一职责、接口隔离、依赖倒转、里氏替换、开闭原则、迪米特法则、合成复用)、UML类图(类的依赖、泛化和实现、类的关联、聚合和组合) 23种设计模式包括:创建型模式:单例模式(8种实现)抽象工厂模式、原型模式、建造者模式、工厂模式。结构型模式:适配器模式(3种实现)、桥接模式、装饰模式、组合模式、外观模式、享元模式、代理模式(3种实现)。行为型模式:模版方法模式、命令模式、访问者模式、迭代器模式、观察者模式、中介者模式、备忘录模式、解释器模式(Interpreter模式)、状态模式、策略模式、职责链模式(责任链模式) 2) 学习目标:通过学习,学员能掌握主流设计模式,规范编程风格,提高优化程序结构和效率的能力
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

小智RE0-走在路上

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

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

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

打赏作者

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

抵扣说明:

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

余额充值