工厂模式

工厂模式有三种:简单工厂模式、工厂方法模式、抽象工厂模式

简单工厂

  • 定义
    类创建模式,用来创建其他类的实例,通过不同的特征返回不同类的实例,被返回类具有相同的父类
  • 角色
    1. 产品的父类
    2. 产品的具体类
    3. 工厂类
  • 优点
    1. 工厂类含有必要的判断逻辑,可以决定在什么时候创建哪一个产品类的实例,客户端可以免除直接创建产品对象的责任,而仅仅“消费”产品;简单工厂模式通过这种做法实现了对责任的分割,它提供了专门的工厂类用于创建对象。
    2. 客户端无需知道所创建的具体产品类的类名,只需要知道具体产品类所对应的参数即可,对于一些复杂的类名,通过简单工厂模式可以减少使用者的记忆量。
    3. 通过引入配置文件,可以在不修改任何客户端代码的情况下更换和增加新的具体产品类,在一定程度上提高了系统的灵活性。
  • 缺点
    1. 由于工厂类集中了所有产品创建逻辑,一旦不能正常工作,整个系统都要受到影响。
    2. 使用简单工厂模式将会增加系统中类的个数,在一定程序上增加了系统的复杂度和理解难度。
    3. 系统扩展困难,一旦添加新产品就不得不修改工厂逻辑,在产品类型较多时,有可能造成工厂逻辑过于复杂,不利于系统的扩展和维护。
    4. 简单工厂模式由于使用了静态工厂方法,造成工厂角色无法形成基于继承的等级结构。
  • 简单工厂模式的适用环境
    1. 工厂类负责创建的对象比较少:由于创建的对象较少,不会造成工厂方法中的业务逻辑太过复杂;
    2. 客户端只知道传入工厂类的参数,对于如何创建对象不关心:客户端既不需要关心创建细节,甚至连类名都不需要记住,只需要知道类型所对应的参数。
  • 代码示例:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    /**
    * 产品的父类
    * @author sky
    *
    */
    public interface Job {

    public void work();

    }


    /**
    * 产品的具体子类
    * @author sky
    */
    public class Teacher implements Job {
    @Override
    public void work() {
    System.out.println("I'm teaching...");
    }
    }

    /**
    * 产品的具体子类2
    * @author sky
    */
    public class Programer implements Job {

    @Override
    public void work() {
    System.out.println("I'm Programing...");
    }

    }

    /**
    * 工厂类
    * @author sky
    */
    public class JobFactory {

    public static final int PROGRAMER = 1;

    public static final int TEACHER = 2;

    public static Job create(int identity){
    if(identity==PROGRAMER){
    return new Programer();
    }else if(identity==TEACHER){
    return new Teacher();
    }else{
    return null;
    }
    }

    }

    /**
    * 测试类
    * @author sky
    */
    public class Test {

    /**
    * @param args
    */
    public static void main(String[] args) {
    System.out.println("创建程序员:");
    Job job = JobFactory.create(JobFactory.PROGRAMER);
    job.work();
    System.out.println("创建老师:");
    job =JobFactory.create(JobFactory.TEACHER);
    job.work();
    }

    }
  • 输出:

    1
    2
    3
    4
    创建程序员:
    I'm Programing...
    创建老师:
    I'm teaching...

工厂方法

  • 定义
    定义一个用于创建对象的接口,使类得实例化延迟到之类,由子类来决定实例化哪一个类。
    在工厂方法模式中,核心的工厂类不再负责所有产品的创建,而是将具体创建的工作交给子类去做。这个核心工厂则变为抽象工厂角色,仅负责给出具工厂子类必须实现的接口,而不接触哪一产品创建的细节。
    这种抽象的结果,使这种工厂方法模式可以用来允许系统不修改具体工厂角色的情况下引进新产品,这一特点无疑使得工厂模式具有超过简单工厂模式的优越性。
  • 角色
    1. 工厂接口
    2. 工厂具体子类
    3. 产品接口
    4. 产品具体子类
  • 使用心得
    如果一个对象有许多的子类,但是子类可以划为几类,这时,如果使用简单工厂模式,则会使代码过多,逻辑混乱,此时使用工厂方法则能让代码更有层次感,条例分明。例如,工作可以分为程序员,教师等,程序员又可分为java程序员,C++程序员,教师又可分为语文老师,数学老师,此种情况下使用工厂方法模式比较合适
  • 优点
    1. 在工厂方法模式中,工厂方法用来创建客户所需要的产品,同时还向客户隐藏了哪种具体产品类将被实例化这一细节,用户只需要关心所需产品对应的工厂,无需关心创建细节,甚至无需知道具体产品类的类名。
    2. 基于工厂角色和产品角色的多态性设计是工厂方法模式的关键。它能够使工厂可以自主确定创建何种产品对象,而如何创建这个对象的细节则完全封装在具体工厂内部。工厂方法模式之所以又被称为多态工厂模式,正是因为所有的具体工厂类都具有同一抽象父类。
    3. 使用工厂方法模式的另一个优点是在系统中加入新产品时,无需修改抽象工厂和抽象产品提供的接口,无需修改客户端,也无需修改其他的具体工厂和具体产品,而只要添加一个具体工厂和具体产品就可以了,这样,系统的可扩展性也就变得非常好,完全符合“开闭原则”。
  • 缺点
    1. 在添加新产品时,需要编写新的具体产品类,而且还要提供与之对应的具体工厂类,系统中类的个数将成对增加,在一定程度上增加了系统的复杂度,有更多的类需要编译和运行,会给系统带来一些额外的开销。
    2. 由于考虑到系统的可扩展性,需要引入抽象层,在客户端代码中均使用抽象层进行定义,增加了系统的抽象性和理解难度,且在实现时可能需要用到DOM、反射等技术,增加了系统的实现难度。
  • 工厂方法模式的适用环境
    1. 一个类不知道它所需要的对象的类:在工厂方法模式中,客户端不需要知道具体产品类的类名,只需要知道所对应的工厂即可,具体的产品对象由具体工厂类创建;客户端需要知道创建具体产品的工厂类。
    2. 一个类通过其子类来指定创建哪个对象:在工厂方法模式中,对于抽象工厂类只需要提供一个创建产品的接口,而由其子类来确定具体要创建的对象,利用面向对象的多态性和里氏代换原则,在程序运行时,子类对象将覆盖父类对象,从而使得系统更容易扩展。
    3. 将创建对象的任务委托给多个工厂子类中的某一个,客户端在使用时可以无需关心是哪一个工厂子类创建产品子类,需要时再动态指定,可将具体工厂类的类名存储在配置文件或数据库中。
  • 代码示例

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    /**
    * 产品的父类
    * @author sky
    *
    */
    public interface Job {

    public void work();

    }

    /**
    * 产品的具体子类1
    * @author sky
    */
    public class ChineseTeacher implements Job {

    @Override
    public void work() {
    System.out.println("I'm a chinese teacher");
    }

    }

    /**
    * 产品的具体子类2
    * @author sky
    */
    public class MathTeacher implements Job {

    @Override
    public void work() {
    System.out.println("I'm a math teacher");
    }

    }

    /**
    * 产品的具体子类3
    * @author sky
    */
    public class CProgramer implements Job {

    @Override
    public void work() {
    System.out.println("I'm a C programer");
    }

    }

    /**
    * 产品的具体子类4
    * @author sky
    */
    public class JavaProgramer implements Job {

    @Override
    public void work() {
    System.out.println("I'm a java programer");
    }

    }

    /**
    * 工厂接口
    * @author sky
    *
    */
    public interface JobFactory {

    public Job create(int type);

    }

    /**
    * 工厂具体子类1 程序员工厂
    * @author sky
    */
    public class ProgramerFactory implements JobFactory {

    public static final int JAVA = 1;

    public static final int C = 2;

    @Override
    public Job create(int type) {

    if(type == JAVA){
    return new JavaProgramer();
    }else if(type == C){
    return new CProgramer();
    }
    return null;
    }

    }

    /**
    * 工厂具体子类2 教师工厂
    * @author sky
    */
    public class TeacherFactory implements JobFactory {

    public static final int MATH = 1;

    public static final int CHINESE = 2;

    @Override
    public Job create(int type) {

    if(type == MATH){
    return new MathTeacher();
    }else if(type == CHINESE){
    return new ChineseTeacher();
    }
    return null;
    }

    }

    /**
    * 测试代码
    * @author sky
    */
    public class Test {

    public static void main(String[] args) {
    System.out.println("请创建一个java程序员");
    JobFactory jf = new ProgramerFactory();
    Job job = jf.create(ProgramerFactory.JAVA);
    job.work();
    System.out.println("请创建一个C程序员");
    job = jf.create(ProgramerFactory.C);
    job.work();
    jf = new TeacherFactory();
    System.out.println("请创建一个语文老师");
    job = jf.create(TeacherFactory.CHINESE);
    job.work();
    System.out.println("请创建一个数学老师");
    job = jf.create(TeacherFactory.MATH);
    job.work();
    }

    }
  • 输出

    1
    2
    3
    4
    5
    6
    7
    8
    请创建一个java程序员
    I'm a java programer
    请创建一个C程序员
    I'm a C programer
    请创建一个语文老师
    I'm a chinese teacher
    请创建一个数学老师
    I'm a math teacher

抽象工厂

  • 定义
    提供一个接口,创建一系列相关连的产品(产品族),而不必指定具体的类。通常,产品族是某个产品的组成部分,比如一个电脑的CPU,内测,硬盘等,一个开发团队的前端、后端、美术等
  • 角色
    1. 工厂接口
    2. 工厂具体子类
    3. 产品接口
    4. 产品具体子类
  • 优点
    1. 隔离了具体类的生成,使得用户不需要知道什么被创建了。
    2. 当一个产品族中的多个对象被设计成一起工作时,它能够保证客户端始终只使用同一个产品族中的对象。
  • 缺点
    添加新的产品对像时,难以扩展抽象工厂以便生产新种类的产品。
  • 抽象工厂模式的适用环境
    1. 一个系统不应当依赖于产品类实例如何被创建、组合和表达的细节。这对于所有形态的工厂模式都是重要的;
    2. 一个系统的产品有多于一个的产品族,而系统只消费其中某一族的产品;
    3. 同属于同一个产品族的产品是在一起使用的,这一约束必须要在系统的设计中体现出来;
    4. 系统提供一个产品类的库,所有的产品以同样的接口出现,从而使客户端不依赖于实现。
  • 代码示例

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    /**
    * 前端接口
    * @author sky
    */
    public interface Client {

    public void doClient();
    }

    /**
    * 前端具体子类
    * @author sky
    */
    public class JuniorClient implements Client {

    @Override
    public void doClient() {
    System.out.println("I'm a junior client");
    }

    }

    /**
    * 后端接口
    * @author sky
    */
    public interface Server {

    public void doServer();
    }

    /**
    *后端具体子类
    * @author sky
    */
    public class JuniorServer implements Server {

    @Override
    public void doServer() {
    System.out.println("I'm a junior server");
    }

    }

    /**
    * 团队工厂接口
    * @author sky
    */
    public interface TeamFactory {

    /**
    * 创建客户端,如果有多个对象选择,这里可以添加参数,子类中根据具体的参数返回对应的对象
    * @return
    */
    public Client createClient();

    /**
    * 创建服务端,如果有多个对象选择,这里可以添加参数,子类中根据具体的参数返回对应的对象
    * @return
    */
    public Server createServer();
    }

    /**
    * 团队工厂具体子类
    * @author sky
    */
    public class JuniorTeamFactory implements TeamFactory {

    @Override
    public Client createClient() {
    return new JuniorClient();
    }

    @Override
    public Server createServer() {
    return new JuniorServer();
    }

    }

    /**
    * 测试类
    * @author sky
    */
    public class Test {

    public static void main(String[] args) {
    System.out.println("我要创建一个初级团队,包括一个初级前端,一个初级服务端");
    TeamFactory tf = new JuniorTeamFactory();
    Client client = tf.createClient();
    Server server = tf.createServer();
    client.doClient();
    server.doServer();
    }

    }
  • 输出

    1
    2
    3
    我要创建一个初级团队,包括一个初级前端,一个初级服务端
    I'm a junior client
    I'm a junior server