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

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

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


前言

单例模式也是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 :[email protected]

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

你可能感兴趣的:(【设计模式(三)】工厂模式)