设计模式--工厂模式

一、概述

工厂模式是我们最常用的实例化对象模式了,是用工厂方法代替new操作的一种模式。著名的Jive论坛 ,就大量使用了工厂模式,工厂模式在Java程序系统可以说是随处可见。因为工厂模式就相当于创建实例对象的new,我们经常要根据类Class生成实例对象,如A a=new A() 工厂模式也是用来创建实例对象的,所以以后new时就要多个心眼,是否可以考虑使用工厂模式,虽然这样做,可能多做一些工作,但会给你系统带来更大的可扩展性和尽量少的修改量。

简单来说:工厂就是一种创建型的设计模式,常用于封装变化,一般遵循那里有变化就封装那里的原则。这里我们以一个快餐店为示例讲解,FastFood表示快餐,KFC表示肯德基,Mac表示麦当劳。

FastFood.java代码如下:

package com.Design_mode.Factory_pattern;

//快餐
public abstract class FastFood {

    //品牌
    public String brand;

    //展示
    public abstract void show();

}

KFC.java代码如下:

package com.Design_mode.Factory_pattern;

public class KFC extends FastFood {
    @Override
    public void show() {
        this.brand = "肯德基";
        System.out.println("欢迎来到"+ this.brand);
    }
}

Mac.java代码如下:

package com.Design_mode.Factory_pattern;

public class Mac extends FastFood {

    @Override
    public void show() {
        this.brand = "麦当劳";
        System.out.println("欢迎来到"+ this.brand);
    }

}

Student.java代码如下:

package com.Design_mode.Factory_pattern;

public class Student {

    public static void main(String[] args) {
        KFC kfc = new KFC();
        kfc.show();
    }

}

运行结果:

 从Student类中可以看到学生只允许吃KFC,如果他想吃别的东西就不允许了,违背DIP(依赖倒转原则),解决:

package com.Design_mode.Factory_pattern;

public class Student {

    public static void main(String[] args) {
        //这里可以指定任意FastFood子类,LSP
        //如果这里是稳定的,不会经常变化,则代码是没有问题的
        //如果这里要不断的变化,new KFC(),new Mac,new Kongfu()...
        FastFood kfc = new KFC();
        kfc.show();
    }

}

new KFC()就是一个变化点,封装。

二、简单工厂(Simple Factory)

简单工厂并不是GOF所著的书中提出的一种设计模式,但这种模式是学习设计模式一个很好的入口点,让我们能更容易理解设计模式是如何达到设计原则的要求的。
简单工厂设计模式是一种创建型的模式,主要是用来解决对象的创建问题。

 

上面的类图反映的就是将一组相似对象(继承自同一个类)的实例的创建放到另外一个对象中完成,即通过 ProductFactory 这个类来按需创建对象

 

在第一节中我们提出了“封装变化”的概念,这里使用简单工厂解决问题,代码如下:

 FastFoodFactory.java代码如下:

package com.Design_mode.Factory_pattern;

/**
 * 快餐工厂
 */
public class FastFoodFactory {
    /***
     * 用于实现不同类型快餐品牌的创建
     * @param brand 类型
     * @return 快餐品牌
     */
    public static FastFood GetFastFood(String brand) {
        switch (brand) {
            case "KFC":
                return new KFC();
            case "Mac":
                return new Mac();
            default:
                throw new IllegalArgumentException("没有该品牌");
        }
    }

}

Student.java代码如下

package com.Design_mode.Factory_pattern;

import java.util.Scanner;

public class Student {

    public static void main(String[] args) {
        //这里可以指定任意FastFood子类,LSP
        //如果这里是稳定的,不会经常变化,则代码是没有问题的
        //如果这里要不断的变化,new KFC(),new Mac,new Kongfu()...
        Scanner input=new Scanner(System.in);
        System.out.print("您想吃什么:");
        String brand=input.next();

        FastFood kfc = FastFoodFactory.GetFastFood(brand);
        kfc.show();
    }

}

运行结果:

简单工厂的优点:

简单工厂的工厂类中包含了必要的逻辑判断,这样就可以根据客户端的选择条件来动态的实例化相关的类,对于客户端来说,其去除了与具体产品之间的依赖

简单工厂的缺点:

违背了开-闭原则

三、工厂方法(Factory Method)

工厂方法模式,定义了一个用于创建对象的接口,让子类来决定要实例化哪一个类,工厂方法让类把实例化延迟到其子类。

在工厂方法模式中主要有以下几个组成部分:

抽象工厂:是工厂方法模式的核心,任何在模式中创建的具体工厂必须实现这个接口。

具体工厂:这是实现抽象工厂接口的具体工厂类,包含与应用程序密切相关的逻辑,并且受到应用程序调用以创建产品对象。

抽象产品:方法方法模式所要创建的对象的父类型,也就是产品对象的共同父类或共同拥有的接口。

具体产品:这是实现了抽象产品所定义的接口的具体产品类的实例。这是客户端最终需要的东西。

示例:

KFC肯德基,Mac麦当劳,Chips薯条,Ham汉堡

Chips.java代码如下:

package com.Design_mode.Factory_pattern;

/**
 * 抽象产品,薯条
 */
public abstract class Chips {

    /**
     * 显示薯条信息
     */
    public abstract void info();

}

KFCChips.java代码如下:

package com.Design_mode.Factory_pattern;

public class KFCChips extends Chips {
    @Override
    public void info() {
        System.out.println("肯德基薯条");
    }
}

MacChips.java代码如下:

package com.Design_mode.Factory_pattern;

public class MacChips extends Chips {
    @Override
    public void info() {
        System.out.println("麦当劳薯条");
    }
}

Ham.java代码如下:

package com.Design_mode.Factory_pattern;

/**
 * 抽象产品,汉堡
 */
public abstract class Ham {

    /**
     * 显示汉堡信息
     */
    public abstract void show();

}

KFCHam.java代码如下:

package com.Design_mode.Factory_pattern;

public class KFCHam extends Ham {
    @Override
    public void show() {
        System.out.println("肯德基汉堡");
    }
}

MacHam.java代码如下:

package com.Design_mode.Factory_pattern;

public class MacHam extends Ham {
    @Override
    public void show() {
        System.out.println("麦当劳汉堡");
    }
}

FastFoodFactoryAb.java代码如下:

package com.Design_mode.Factory_pattern;

/**
 * 抽象工厂 快餐工厂
 */
public abstract class FastFoodFactoryAb {

    /**
     * 生产汉堡
     */
    public abstract Ham CreateHam();

    /**
     * 生产薯条
     */
    public abstract Chips CreateChips();

    /***
     * 用于实现不同类型快餐品牌的创建
     * @param brand 类型
     * @return 快餐品牌
     */
    public static FastFoodFactoryAb GetFastFood(String brand) {
        switch (brand) {
            case "KFC":
                return new KFCFactory();
            case "Mac":
                return new MacFactory();
            default:
                throw new IllegalArgumentException("没有该品牌");
        }
    }
}

KFCFactory.java代码如下:

package com.Design_mode.Factory_pattern;

public class KFCFactory extends FastFoodFactoryAb {
    @Override
    public Ham CreateHam() {
        return new KFCHam();
    }

    @Override
    public Chips CreateChips() {
        return new KFCChips();
    }
}

MacFactory.java代码如下:

package com.Design_mode.Factory_pattern;

public class MacFactory extends FastFoodFactoryAb {
    @Override
    public Ham CreateHam() {
        return new MacHam();
    }

    @Override
    public Chips CreateChips() {
        return new MacChips();
    }
}

Student.java代码如下:

package com.Design_mode.Factory_pattern;

import java.util.Scanner;

public class Student {

    public static void main(String[] args) {
        //这里可以指定任意FastFood子类,LSP
        //如果这里是稳定的,不会经常变化,则代码是没有问题的
        //如果这里要不断的变化,new KFC(),new Mac,new Kongfu()...
        Scanner input=new Scanner(System.in);
        System.out.print("您想吃什么:");
        String brand=input.next();

        FastFoodFactoryAb fastFood = FastFoodFactoryAb.GetFastFood(brand);
        fastFood.CreateHam().show();
        fastFood.CreateChips().info();
    }

}

运行结果:

原文来自:https://www.cnblogs.com/best/p/7762841.html

原文地址:https://www.cnblogs.com/Qi1007/p/10093027.html