【设计模式(三)】工厂模式

【设计模式(三)】工厂模式

个人学习笔记分享,当前能力有限,请勿贬低,菜鸟互学,大佬绕道

如有勘误,欢迎指出和讨论,本文后期也会进行修正和补充


前言

单例模式也是Java最简单和常见的模式之一

这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。

在工厂模式中,我们在创建对象时不会对客户端暴露创建逻辑,并且是通过使用一个共同的接口来指向新创建的对象

根据产品类型和抽象成都可分为简单工厂模式工厂方法模式抽象工厂模式

实际上前面介绍的单例模式,也属于工厂模式。


1.介绍

使用目的:定义一个创建对象的接口,让其子类自己决定实例化哪一个工厂类,工厂模式使其创建过程延迟到子类进行

使用时机:需要根据不同场景创建不同的实例

解决问题:创建子类的时候,必须明确知道是哪个类,再调用对应的方法,积少成多后管理和维护极其麻烦

实现方法:子类都是用一个工厂类的一个接口创建,输入不同的条件,然后接口返回对应的子类实例对象

应用实例:

  • 管理设备,用户只需要知道设备型号即可,而不需要知道具体的产品名和设备参数
  • 策略管理,对于不同的策略,仅仅知道其唯一标识即可获取实例,而不需要知道具体策略是怎样的

优点

  • 一个调用者想创建一个对象,只要知道其名称就可以了
  • 扩展性高,如果想增加一个产品,只要扩展一个工厂类就可以
  • 屏蔽产品的具体实现,调用者只关心产品的接口。

缺点:随着产品越来越多

  • 类的数量会越来越多,依然会造成管理困难的问题
  • 系统的复杂度和抽象程度越来越高,简单点说就是。。。看不懂了。。。
  • 增加了系统具体类的依赖,也就是耦合度增加了,这并不是一件好事情

作为一种创建类模式,在任何需要生成复杂对象的地方,都可以使用工厂方法模式,但因为其缺点的存在,简单对象建议直接new就好了


2.简单工厂模式

2.1.简介

专门定义一个类用来创建其它类的实例,被创建的实例通常都具有共同的父类。调用工厂类的方法,输入必要的信息,输出对应的实例。

包括三个角色

  • 抽象产品接口:声明所有产品的公共方法
  • 具体产品类:按照自己的需求实现抽象接口的方法
  • 工厂:提供公共方法用于按照不同条件生产产品

2.2.实现

  1. 创建接口,作为标准规范类(AbstractProduct)

    public interface Animal {
        void say();
    }
    
  2. 创建子类Dog.class,实现接口

    public class Dog implements Animal {
        @Override
        public void say() {
            System.out.println("汪!");
        }
    }
    
  3. 创建子类Cat.class,实现接口

    public class Cat implements Animal {
        @Override
        public void say() {
            System.out.println("喵!");
        }
    }
    
  4. 创建工厂类AnimalFactory.class,用于创建实例

    public class AnimalFactory {
        public Animal createAnimal(String name) {
            Animal animal = null;
            switch (name) {
                case "dog":
                    animal = new Dog();
                    break;
                case "cat":
                    animal = new Cat();
                    break;
                default:
                    break;
            }
            return animal;
        }
    }
    
  5. 测试类FactoryTest.class

    public class FactoryTest {
        public static void main(String[] args) {
            AnimalFactory factory=new AnimalFactory();
            Animal dog = factory.createAnimal("dog");
            dog.say();
            Animal cat = factory.createAnimal("cat");
            cat.say();
        }
    }
    

完整样例

package com.company.factory;

/**
 * 接口,标准规范类
 */
interface Animal {
    void say();
}

/**
 * 子类1
 */
class Dog implements Animal {
    @Override
    public void say() {
        System.out.println("汪!");
    }
}

/**
 * 子类2
 */
class Cat implements Animal {
    @Override
    public void say() {
        System.out.println("喵!");
    }
}

/**
 * 工厂
 */
class AnimalFactory {
    public Animal createAnimal(String name) {
        Animal animal = null;
        switch (name) {
            case "dog":
                animal = new Dog();
                break;
            case "cat":
                animal = new Cat();
                break;
            default:
                break;
        }
        return animal;
    }
}

/**
 * 测试类
 */
public class FactoryTest {
    public static void main(String[] args) {
        AnimalFactory factory = new AnimalFactory();
        Animal dog = factory.createAnimal("dog");
        dog.say();
        Animal cat = factory.createAnimal("cat");
        cat.say();
    }
}

结果

image-20200929142337653

2.3.优点

工厂角色负责产生具体的实例对象,所以在工厂类中需要有必要的逻辑,通过客户的输入能够得到具体创建的实例;所以客户端就不需要感知具体对象是如何产生的,只需要将必要的信息提供给工厂即可


2.4.缺点

简单工厂模式是违反“开闭原则”,即对扩展开放,对修改关闭;因为如果要新增具体产品,就需要修改工厂类的代码,而不是在外部进行扩展

因此,衍生出了工厂方法模式,用于弥补解决这个缺点


3.工厂模式

3.1.介绍

工厂方法模式是对简单工厂模式进一步的解耦

定义一个用来创建对象的接口,让子类决定实例化哪一个类,让子类决定实例化延迟到子类。

工厂方法模式是针对每个产品提供一个工厂类,使用时判断用哪个工厂类去创建对象

包括四个角色

  • 抽象产品接口:声明所有产品的公共方法
  • 具体产品类:按照自己的需求实现抽象接口的方法
  • 抽象工厂接口:声明所有公共内场的公共创建方法
  • 具体工厂类:按照产品的需求实现抽象工厂的方法

3.2.实现

  1. 定义抽象产品接口

    interface Animal {
        void say();
    }
    
  2. 定义两个产品子类,实现抽象产品方法

    class Dog implements Animal {
        @Override
        public void say() {
            System.out.println("汪!");
        }
    }
    
    class Cat implements Animal {
        @Override
        public void say() {
            System.out.println("喵!");
        }
    }
    
  3. 定义抽象工厂接口

    interface AnimalFactory {
        Animal createAnimal();
    }
    
  4. 定义两个工厂子类,实现抽象工厂方法

    class DogFactory implements AnimalFactory {
        @Override
        public Animal createAnimal() {
            return new Dog();
        }
    }
    
    class CatFactory implements AnimalFactory {
        @Override
        public Animal createAnimal() {
            return new Cat();
        }
    }
    
  5. 测试类

    public class FactoryTest2 {
        public static void main(String[] args) {
            AnimalFactory dogFactory = new DogFactory();
            Animal dog = dogFactory.createAnimal();
            dog.say();
    
            AnimalFactory catFactory = new CatFactory();
            Animal cat = catFactory.createAnimal();
            cat.say();
        }
    }
    

完整代码

package com.company.factory;

/**
 * 接口,标准规范类
 */
interface Animal {
    void say();
}

/**
 * 子类1
 */
class Dog implements Animal {
    @Override
    public void say() {
        System.out.println("汪!");
    }
}

/**
 * 子类2
 */
class Cat implements Animal {
    @Override
    public void say() {
        System.out.println("喵!");
    }
}

/**
 * 公共工厂接口
 */
interface AnimalFactory {
    Animal createAnimal();
}

/**
 * 工厂1
 */
class DogFactory implements AnimalFactory {
    @Override
    public Animal createAnimal() {
        return new Dog();
    }
}

/**
 * 工厂2
 */
class CatFactory implements AnimalFactory {
    @Override
    public Animal createAnimal() {
        return new Cat();
    }
}

/**
 * 测试类
 */
public class FactoryTest2 {
    public static void main(String[] args) {
        AnimalFactory dogFactory = new DogFactory();
        Animal dog = dogFactory.createAnimal();
        dog.say();

        AnimalFactory catFactory = new CatFactory();
        Animal cat = catFactory.createAnimal();
        cat.say();
    }
}

运行结果

image-20200929153943337

3.3.优点

  • 工厂方法用来创建客户所需要的产品,同时隐藏了哪种具体产品类将被实例化的细节,用户只需要要关注工厂,不需要关注创建的细节
  • 在增加和修改子类的时候不用修改其他产品和工厂的代码,只需要增加和修改自身产品和工厂就好,完全符合开放—封闭性原则
  • 创建对象的细节完全封装在具体的工厂内部,而且有了抽象的工厂类,所有的具体工厂都继承了自己的父类,完美的体现了多态性

3.4.缺点

  • 在增加新的产品时,也必须增加新的工厂类,会带来额外的开销
  • 抽象层的加入使得理解程度加大

4.抽象工厂模式

4.1.介绍

抽象工厂模式是工厂方法模式的进一步延伸,提供功能更为强大的工厂类并且具备较好的可扩展性

说白了就是在抽象工厂接口中定义方法,使得每次添加一类产品,只需要在工厂接口中新增一个创建产品的接口,并在具体子工厂中实现新产品的创建即可


4.2.实现

跟工厂方法基本一致,直接贴全部代码了

package com.company.factory;

/**
 * 接口,标准规范类
 */
interface Animal {
    void say();
}

/**
 * 子类1
 */
class Dog implements Animal {
    @Override
    public void say() {
        System.out.println("汪!");
    }
}

/**
 * 子类2
 */
class Cat implements Animal {
    @Override
    public void say() {
        System.out.println("喵!");
    }
}
/**
 * 接口,标准规范类
 */
interface Food {
    void feed();
}

/**
 * 子类1
 */
class DogFood implements Food {
    @Override
    public void feed() {
        System.out.println("meat!");
    }
}

/**
 * 子类2
 */
class CatFood implements Food {
    @Override
    public void feed() {
        System.out.println("fish!");
    }
}
/**
 * 公共工厂接口
 */
interface AnimalFactory {
    Animal createAnimal();
    Food createFood();
}

/**
 * 工厂1
 */
class DogFactory implements AnimalFactory {
    @Override
    public Animal createAnimal() {
        return new Dog();
    }

    @Override
    public Food createFood() {
        return new DogFood();
    }
}

/**
 * 工厂2
 */
class CatFactory implements AnimalFactory {
    @Override
    public Animal createAnimal() {
        return new Cat();
    }

    @Override
    public Food createFood() {
        return new CatFood();
    }
}

/**
 * 测试类
 */
public class FactoryTest2 {
    public static void main(String[] args) {
        AnimalFactory dogFactory = new DogFactory();
        Animal dog = dogFactory.createAnimal();
        dog.say();
        Food dogFood=dogFactory.createFood();
        dogFood.feed();

        AnimalFactory catFactory = new CatFactory();
        Animal cat = catFactory.createAnimal();
        cat.say();
        Food catFood=catFactory.createFood();
        catFood.feed();
    }
}

结果

image-20200929165621203

4.3.优点

  1. 易于添加产品类别,除了产品类本身以外,只需要在工厂接口中添加对应的方法,并加以实现即可
  2. 创建实例的过程与客户端分离,客户端只需要知道是哪种产品就行了,而无需知道如何创建的

4.4.缺点

  1. 添加产品子类较麻烦,如我想添加一个子类panda,那么我需要增加对应的子类,还需要增加对应的工厂类
  2. 使用时需要生成产品对应的工厂类,如果有N种产品则需要N个工厂类

其实还了解到一些在此基础上的变型,比如所有产品使用同一个接口,根据接收到的数据直接映射出产品,添加产品也就不用修改工厂了,但这样已经违背了工厂模式的初衷,即统一管理,有兴趣可以试试,但此处不多做阐述


5.后记

大部分引入的依赖或者工具类等,都会使用工厂模式,来隐藏细节,而仅提供给我们创建和使用方法

这样我们无需知道具体如何实现(虽然自己去看源码是个好习惯),仅仅知晓所提供给我们的公共方法即可掌握其使用方法,方便快捷

自己码代码的时候,不一定非得遵从工厂模式,但这种隐藏细节,而仅提供使用方法接口的做法,是值得我们学习的好习惯



作者:Echo_Ye

WX:Echo_YeZ

EMAIL :echo_yezi@qq.com

个人站点:在搭了在搭了。。。(右键 - 新建文件夹)

posted @ 2020-09-29 17:49  Echo_Ye  阅读(96)  评论(0编辑  收藏  举报