简单工厂模式&&抽象工厂模式

一.简单工厂模式

1.什么是工厂模式

工厂模式的核心就是把对象的生产过程交给工厂来完成,当外部需要一个对象时,由工厂提供接口来获取对象,这样一来即使生产对象的过程变了,仍然不影响外部对对象的获取和使用。

2.举个栗子

定义Chef(厨师),Coder(程序员)两个类。

/**
 * 厨师实体类
 */
public class Chef {
    /**
     * 提供一个做事情的方法
     */
    public void doSometing(){
        System.out.println("厨师正在烹调食物...");
    }
}
/**
 *  程序员实体类
 */
public class Coder {
    /**
     * 提供一个做事情的方法
     */
    public void doSometing(){
        System.out.println("程序员正在编写程序...");
    }
}

如果我们要在其它地方使用这两个类,一般我们会这样做。

/**
 * 测试类
 */
public class Test {
    public static void main(String[] args) {
        // 创建“厨师”对象
        Chef chef = new Chef();
        // 创建“程序员”对象
        Coder coder = new Coder();

        // 分别调用各自的操作方法
        chef.doSometing();
        coder.doSometing();
    }
}

感觉没有什么其它问题!现在新的需求来了。业务线需要在每个创建对象的地方加上日志,并且还要修改Coder的名字为UICoder,我们应该怎么做呢?假如有很多地方使用了上面创建对象的代码,是不是业务代码都要修改一遍?

此时引入我们的“工厂模式”!

2.1.引入“简单工厂模式”重构代码

2.1.1.定义用户接口并提供一个操作方法。

/**
 * 定义一个用户接口
 */
public interface IUser {
    /**
     * 提供一个操作方法
     */
    void doSometing();
}

2.1.2.Chef,Coder实现该接口并重写操作方法

/**
 * 厨师实体类
 */
public class Chef implements IUser {
    /**
     * 提供一个做事情的方法
     */
    @Override
    public void doSometing(){
        System.out.println("厨师正在烹调食物...");
    }
}
/**
 *  程序员实体类
 */
public class Coder implements IUser {
    /**
     * 提供一个做事情的方法
     */
    @Override
    public void doSometing(){
        System.out.println("程序员正在编写程序...");
    }
}

2.1.3.定义工厂方法用于创建对象

/**
 * 定义工厂类
 */
public class UserFactory {
    public static IUser createUser(String userType){
        IUser user = null;
        switch (userType){
            case "Chef" :
                user = new Chef();
                break;
            case "Coder" :
                user = new Coder();
                break;
        }
        return user;
    }
}

2.1.4.测试

/**
 * 测试类
 */
public class Test {
    public static void main(String[] args) {
        IUser chef = UserFactory.createUser("Chef");
        IUser coder = UserFactory.createUser("Coder");
        chef.doSometing();
        coder.doSometing();
    }
}

可以看到业务调用方不依赖Chef和Coder了,并且没有了具体的对象创建过程,我们只是让工厂返回我们需要的对象,我们去使用就可以了至于对象的创建过程我们并不关心。回到上面的问题以后不管是创建对象前加日志,还是修改对象的名称,调用方的业务代码不需要更改只需要改工厂类相关的代码就可以了。

3.简单工厂模式总结

它把对象的创建过程封装起来,隐藏了对象创建的细节,根据外部传入的参数来决定返回哪一种对象,它的缺点就是如果要增加对象类型,或者修改某一个对象的创建方法时,就必须修改工厂类,这不符合对象编程设计原则之一的“开闭原则”。

开闭原则:对扩展开放,对修改封闭。在实现新的需求的时候,最好能够只是扩展而不去修改已经写好的代码,这样能够把新需求带来的风险降到最低。

二.抽象工厂模式

由上“简单工厂模式”可以看出,“厨师”,“程序员”对象都是在同一个工厂里面去生产。一旦生产“厨师”对象的工厂代码发生变化。就有可能影响到“程序员”对象的生产。因为都是使用的是同一个工厂,可能存在误改的情况。为了解决这个问题我们可以建两个工厂一个负责“厨师”另一个负责“程序员”对象的生产。这样就实现了解耦合。当修改生产“厨师”对象的工厂代码时不会影响到“程序员”工厂代码。因为两者是分开的。

上面的概念其实就是“抽象工厂模式”。抽象工厂把具体工厂需要做的事情定义好,所有具体的工厂都必须要实现抽象工厂里面的方法,这样业务调用方依赖的是抽象工厂而不是具体的工厂,实现了解耦合。

1.举个栗子

将“简单工厂”改造为“抽象工厂”。

/**
 * 工厂总接口,后续工厂实现此接口用于产生不同的对象
 */
public interface IFactory {
    /**
     * 创建对象方法
     */
     IUser createUser();
}
/**
 * 定义厨师工厂,用于产生“厨师”对象
 */
public class ChefFactory implements IFactory{

    @Override
    public IUser createUser() {
        Chef chef = new Chef();
        return chef;
    }
}
/**
 * 定义程序员工厂,用于产生“程序员”对象
 */
public class CoderFactory implements IFactory{

    @Override
    public IUser createUser() {
        Coder coder = new Coder();
        return coder;
    }
}
/**
 * 定义一个用户接口
 */
public interface IUser {
    /**
     * 提供一个行为方法,后续新加的其它用户类型都实现此接口用于表达不同用户做不同事
     */
    void doSometing();
}
/**
 * 厨师实体类
 */
public class Chef implements IUser {
    /**
     * 实现IUser接口中做事情的方法
     */
    @Override
    public void doSometing(){
        System.out.println("厨师正在烹调食物...");
    }
}
/**
 *  程序员实体类
 */
public class Coder implements IUser {
    /**
     * 实现IUser接口中做事情的方法
     */
    @Override
    public void doSometing(){
        System.out.println("程序员正在编写程序...");
    }
}
/**
 * 测试类
 */
public class Test {
    public static void main(String[] args) {
        // 创建工厂对象
        IFactory chefFactory = new ChefFactory();
        // 通过工厂创建“厨师”对象
        IUser chefUser = chefFactory.createUser();
        // 执行业务方法
        chefUser.doSometing();

        // 创建工厂对象
        CoderFactory coderFactory = new CoderFactory();
        // 通过工厂创建“程序员”对象
        IUser coderUser = coderFactory.createUser();
        // 执行业务方法
        coderUser.doSometing();
    }
}

2.抽象工厂模式总结

业务调用处需要具体的对象时就使用具体工厂类去创建对象,因为不同工厂是分开的当修改某个具体工厂时不会影响到其它工厂。抽象工厂模式的缺点也很明显,当新增一种对象的生产时需要额外增加一个具体的工厂类,如果新增的对象很多那么具体的工厂类就会非常多。其次它把具体的工厂对象创建过程暴露给了业务调用处,不利于解耦合。

最近更新

  1. TCP协议是安全的吗?

    2024-04-20 19:26:06       18 阅读
  2. 阿里云服务器执行yum,一直下载docker-ce-stable失败

    2024-04-20 19:26:06       19 阅读
  3. 【Python教程】压缩PDF文件大小

    2024-04-20 19:26:06       18 阅读
  4. 通过文章id递归查询所有评论(xml)

    2024-04-20 19:26:06       20 阅读

热门阅读

  1. 记录golang日常错误处理

    2024-04-20 19:26:06       15 阅读
  2. 什么是三高架构

    2024-04-20 19:26:06       14 阅读
  3. Redis中cluster命令详解

    2024-04-20 19:26:06       13 阅读
  4. 2024年想要开视频号小店,需要准备什么东西?

    2024-04-20 19:26:06       15 阅读
  5. springboot发送邮件

    2024-04-20 19:26:06       15 阅读
  6. CentOS在配置文件中添加环境变量

    2024-04-20 19:26:06       23 阅读
  7. 前端面试常见问题

    2024-04-20 19:26:06       11 阅读
  8. Git学习笔记

    2024-04-20 19:26:06       13 阅读
  9. docker 容器中安装cron,却无法启动定时任务

    2024-04-20 19:26:06       14 阅读