工厂设计模式

简单工厂模式

简单工厂不是一种设计模式,反而比较像是一种编程习惯。
结构

  • 抽象产品 :定义了产品的规范,描述了产品的主要特性和功能。
  • 具体产品 :实现或者继承抽象产品的子类
  • 具体工厂 :提供了创建产品的方法,调用者通过该方法来获取产品。

实现

java 复制代码
public abstract class Coffee {
    public abstract String getName();

    //加糖
    public void addSugar() {
        System.out.println("加糖");
    }

    //加奶
    public void addMilk() {
        System.out.println("加奶");
    }
}
java 复制代码
public class AmericanCoffee extends Coffee {
    @Override
    public String getName() {
        return "美式咖啡";
    }
}
java 复制代码
public class LatteCoffee extends Coffee {
    @Override
    public String getName() {
        return "拿铁咖啡";
    }
}
java 复制代码
public class SimpleCoffeeFactory {

    public Coffee createCoffee(String type) {
        //根据不同的类型创建不同的咖啡对象
        Coffee coffee = null;
        if ("american".equals(type)) {
            coffee = new AmericanCoffee();
        } else if ("latte".equals(type)) {
            coffee = new LatteCoffee();
        } else {
            throw new RuntimeException("对不起,您所点的咖啡没有");
        }
        return coffee;
    }
}
java 复制代码
public class CoffeeStore {

    public Coffee orderCoffee(String type) {
        //创建一个简单工厂对象
        SimpleCoffeeFactory simpleCoffeeFactory = new SimpleCoffeeFactory();
        //根据用户需求获取咖啡对象
        Coffee coffee = simpleCoffeeFactory.createCoffee(type);
        //加配料
        coffee.addMilk();
        coffee.addSugar();
        return coffee;
    }
}
java 复制代码
public class Client {
    public static void main(String[] args) {
        //创建咖啡店对象
        CoffeeStore coffeeStore = new CoffeeStore();
        //点咖啡
        Coffee coffee = coffeeStore.orderCoffee("american");
        System.out.println(coffee.getName());
    }
}

优缺点

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

静态工厂

在开发中也有一部分人将工厂类中的创建对象的功能定义为静态的,这个就是静态工厂模式,它也不是23种设计模式中的。

java 复制代码
public class SimpleCoffeeFactory {

    public static Coffee createCoffee(String type) {
        //根据不同的类型创建不同的咖啡对象
        Coffee coffee = null;
        if ("american".equals(type)) {
            coffee = new AmericanCoffee();
        } else if ("latte".equals(type)) {
            coffee = new LatteCoffee();
        } else {
            throw new RuntimeException("对不起,您所点的咖啡没有");
        }
        return coffee;
    }
}
java 复制代码
public class CoffeeStore {

    public Coffee orderCoffee(String type) {
        Coffee coffee = SimpleCoffeeFactory.createCoffee(type);
        //加配料
        coffee.addMilk();
        coffee.addSugar();
        return coffee;
    }
}

工厂方法模式

概念

定义一个用于创建对象的接口,让子类决定实例化哪个产品类对象。工厂方法使一产品类的实例化延迟到其工厂的子类。

结构

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

实现

java 复制代码
public abstract class Coffee {
    public abstract String getName();

    //加糖
    public void addSugar() {
        System.out.println("加糖");
    }

    //加奶
    public void addMilk() {
        System.out.println("加奶");
    }
}
java 复制代码
public class AmericanCoffee extends Coffee {
    @Override
    public String getName() {
        return "美式咖啡";
    }
}
java 复制代码
public class LatteCoffee extends Coffee {
    @Override
    public String getName() {
        return "拿铁咖啡";
    }
}
java 复制代码
public interface CoffeeFactory {
    //创建咖啡对象的方法
    Coffee createCoffee();
}
java 复制代码
public class AmericanCoffeeFactory implements CoffeeFactory {
    @Override
    public Coffee createCoffee() {
        return new AmericanCoffee();
    }
}
java 复制代码
public class LatteCoffeeFactory implements CoffeeFactory {
    @Override
    public Coffee createCoffee() {
        return new LatteCoffee();
    }
}
java 复制代码
public class CoffeeStore {

    private CoffeeFactory factory;

    public void setFactory(CoffeeFactory factory) {
        this.factory = factory;
    }

    //点咖啡的方法
    public Coffee orderCoffee(){
        Coffee coffee = factory.createCoffee();
        coffee.addMilk();
        coffee.addSugar();
        return coffee;
    }
}
java 复制代码
public class Client {
    public static void main(String[] args) {
        //创建咖啡店对象
        CoffeeStore coffeeStore = new CoffeeStore();
        //创建咖啡工厂对象
        CoffeeFactory factory = new LatteCoffeeFactory();
        //CoffeeFactory factory = new AmericanCoffeeFactory();
        coffeeStore.setFactory(factory);
        Coffee coffee = coffeeStore.orderCoffee();
        System.out.println(coffee.getName());
    }
}

优缺点

优点 :用户只需要知道具体工厂的名称就可得到所要的产品,无须知道产品的具体创建过程;在系统增加新的产品时只需要添加具体产品类和对应的具体工厂类,无须对原工厂进行任何修改,满足开闭原则;
缺点:每增加一个产品就要增加一个具体产品类和一个对应的具体工厂类,这增加了系统的复杂度。

抽象工厂模式

概念

一种为访问类提供一个创建一组相关或相互依赖对象的接口,且访问类无须指定所要产品的具体类就能得到同族的不同等级的产品的模式结构。抽象工厂模式是工厂方法模式的升级版本,工厂方法模式只生产一个等级的产品,而抽象工厂模式可生产多个等级的产品。

结构

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

实现

java 复制代码
public abstract class Coffee {
    public abstract String getName();

    //加糖
    public void addSugar() {
        System.out.println("加糖");
    }

    //加奶
    public void addMilk() {
        System.out.println("加奶");
    }
}
java 复制代码
public class AmericanCoffee extends Coffee {
    @Override
    public String getName() {
        return "美式咖啡";
    }
}
java 复制代码
public class LatteCoffee extends Coffee {
    @Override
    public String getName() {
        return "拿铁咖啡";
    }
}
java 复制代码
public abstract class Dessert {
    public abstract void show();
}
java 复制代码
public class Trimisu extends Dessert {
    @Override
    public void show() {
        System.out.println("提拉米苏");
    }
}
java 复制代码
public class MatchaMousse extends Dessert {
    @Override
    public void show() {
        System.out.println("抹茶慕斯");
    }
}
java 复制代码
public interface DessertFactory {

    //生产咖啡的功能
    Coffee createCoffee();

    //生产甜品的功能
    Dessert createDessert();
}
java 复制代码
public class AmericanDessertFactory implements DessertFactory {
    @Override
    public Coffee createCoffee() {
        return new AmericanCoffee();
    }

    @Override
    public Dessert createDessert() {
        return new MatchaMousse();
    }
}
java 复制代码
public class ItalyDessertFactory implements DessertFactory {
    @Override
    public Coffee createCoffee() {
        return new LatteCoffee();
    }

    @Override
    public Dessert createDessert() {
        return new Trimisu();
    }
}
java 复制代码
public class Client {
    public static void main(String[] args) {
        //创建工厂对象
        //ItalyDessertFactory factory = new ItalyDessertFactory();
        AmericanDessertFactory factory = new AmericanDessertFactory();

        //通过工厂对象创建产品对象
        Coffee coffee = factory.createCoffee();
        Dessert dessert = factory.createDessert();

        System.out.println(coffee.getName());
        dessert.show();
    }
}

优缺点

优点 :当一个产品族中的多个对象被设计成一起工作时,它能保证客户端始终只使用同一个产品族中的对象。
缺点:当产品族中需要增加一个新的产品时,所有的工厂类都需要进行修改。

使用场景

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

如:输入法换皮肤,一整套一起换。生成不同操作系统的程序。

模式扩展

简单工厂+配置文件解除耦合

properties 复制代码
american=pattern.factory.config_factory.AmericanCoffee
latte=pattern.factory.config_factory.LatteCoffee
java 复制代码
public abstract class Coffee {
    public abstract String getName();

    //加糖
    public void addSugar() {
        System.out.println("加糖");
    }

    //加奶
    public void addMilk() {
        System.out.println("加奶");
    }
}
java 复制代码
public class AmericanCoffee extends Coffee {
    @Override
    public String getName() {
        return "美式咖啡";
    }
}
java 复制代码
public class LatteCoffee extends Coffee {
    @Override
    public String getName() {
        return "拿铁咖啡";
    }
}
java 复制代码
public class CoffeeFactory {
    //加载配置文件,获取配置文件中的全类名,并创建该类的对象进行存储。
    //1.定义容器对象存储咖啡对象。
    private static HashMap<String, Coffee> map = new HashMap<>();

    //2.加载配置文件,一次性创建好对象。
    static {
        //创建Properties对象
        Properties p = new Properties();
        //获取配置文件的流对象
        InputStream inputStream = CoffeeFactory.class.getClassLoader().getResourceAsStream("bean.properties");
        //加载配置文件
        try {
            p.load(inputStream);
            //从p集合中获取全类名并创建对象
            Set<Object> keys = p.keySet();
            for (Object key : keys) {
                //获取全类名
                String className = p.getProperty((String) key);
                //通过反射技术创建对象
                Class clazz = Class.forName(className);
                Coffee coffee = (Coffee) clazz.newInstance();
                //将名称和对象存储到容器中
                map.put((String) key, coffee);
            }
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    //根据名称获取对象
    public static Coffee createCoffee(String name) {
        return map.get(name);
    }
}
java 复制代码
public class Client {
    public static void main(String[] args) {
        Coffee coffee = CoffeeFactory.createCoffee("american");
        System.out.println(coffee.getName());

        System.out.println("====================");
        Coffee coffee1 = CoffeeFactory.createCoffee("latte");
        System.out.println(coffee1.getName());
    }
}

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

实例

java 复制代码
public class Demo {
    public static void main(String[] args) {
        List<String> list = new ArrayList<>();
        list.add("令狐冲");
        list.add("风清扬");
        list.add("任我行"); //获取迭代器对象
        Iterator<String> it = list.iterator(); //使用迭代器遍历
        while (it.hasNext()) {
            String ele = it.next();
            System.out.println(ele);
        }
    }
}

使用迭代器遍历集合,获取集合中的元素。而单列集合获取迭代器的方法就使用到了工厂方法模式。

Collection接口是抽象工厂类,ArrayList是具体的工厂类;Iterator接口是抽象商品类,ArrayList类中的Iter内部类是具体的商品类。在具体的工厂类中iterator()方法创建具体的商品类的对象。

1,DateForamt类中的getInstance()方法使用的是工厂模式;

2,Calendar类中的getInstance()方法使用的是工厂模式;

相关推荐
Java中文社群几秒前
Dify实战案例:MySQL查询助手!嘎嘎好用
java·人工智能·后端
程序猿阿伟3 分钟前
《深度探秘:Java构建Spark MLlib与TensorFlow Serving混合推理流水线》
java·spark-ml·tensorflow
TDengine (老段)12 分钟前
TDengine 开发指南—— UDF函数
java·大数据·数据库·物联网·数据分析·tdengine·涛思数据
键盘林15 分钟前
分布式系统简述
java·开发语言
可儿·四系桜16 分钟前
如何在 Java 中优雅地使用 Redisson 实现分布式锁
java·开发语言·分布式
昕冉27 分钟前
利用Axure 9中继器绘制数据统计表原型图
设计模式·设计
sszdzq31 分钟前
SpringCloudGateway 自定义局部过滤器
java·spring boot
消失的旧时光-194338 分钟前
Android 开发中配置 USB 配件模式(Accessory Mode) 配件过滤器的配置
android·java
IDRSolutions_CN44 分钟前
如何在网页里填写 PDF 表格?
java·经验分享·pdf·软件工程·团队开发
-兰天白云-1 小时前
java转pdf工具对比
java