文章详情

短信预约-IT技能 免费直播动态提醒

请输入下面的图形验证码

提交验证

短信预约提醒成功

一文搞懂设计模式—工厂方法模式

2024-11-30 01:27

关注

工厂方法模式属于创建型模式,通过定义一个用于创建对象的接口,将具体的实例化延迟到子类中,提供了一种灵活、可扩展的对象创建方式,使得系统更加符合开闭原则。

使用场景

工厂方法模式适用于以下场景:

一个常见的工厂方法模式在 Spring 中的应用例子是通过 FactoryBean 接口来创建自定义的工厂 Bean。

假设我们有一个名为 UserService 的服务类,它依赖于另一个名为 UserRepository 的数据访问对象。我们可以使用工厂方法模式来创建 UserService 实例,并将其作为一个 Bean 注册到 Spring 容器中。

首先,我们创建一个实现了 FactoryBean 接口的工厂类 UserServiceFactory:

public class UserServiceFactory implements FactoryBean {
    private UserRepository userRepository;

    public void setUserRepository(UserRepository userRepository) {
        this.userRepository = userRepository;
    }

    @Override
    public UserService getObject() throws Exception {
        UserService userService = new UserService();
        userService.setUserRepository(userRepository);
        return userService;
    }

    @Override
    public Class getObjectType() {
        return UserService.class;
    }

    @Override
    public boolean isSingleton() {
        return true;
    }
}

在上述代码中,UserServiceFactory 实现了 FactoryBean 接口,并重写了相关方法。在 getObject() 方法中,我们创建了一个 UserService实例,并设置了其依赖的 UserRepository。getObjectType() 方法返回了工厂创建的对象类型,isSingleton() 方法表示该工厂创建的对象是否为单例。

接下来,我们需要将 UserServiceFactory 和 UserRepository 注册到Spring容器中。可以通过XML配置文件进行配置:




    


在上述配置中,我们首先创建了一个 UserRepository 的Bean,并将其注入到 UserServiceFactory 工厂类中。然后,通过 factory-bean 属性指定使用userServiceFactory 工厂来创建 userService 的实例。

这样,当Spring容器初始化时,会自动调用 UserServiceFactory 的 getObject() 方法来创建 UserService 实例,并将其作为一个 Bean 注册到容器中。可以通过 @Autowired 或其他方式来注入 UserService 对象,并使用它的服务。

通过这种方式,我们成功地应用了工厂方法模式,在 Spring 中管理和创建了 UserService 实例,并解耦了对象的创建和依赖注入过程。

具体实现

工厂方法模式涉及以下几个角色:

在工厂方法模式中,抽象工厂和抽象产品是核心,而具体工厂和具体产品则根据实际需求进行扩展和实现。

通过这些角色的协作,工厂方法模式实现了将产品的创建过程封装起来,使得客户端与具体产品解耦,同时也提供了灵活性和可扩展性。

抽象产品类和具体产品类

首先定义一个抽象产品类 Product:

public abstract class Product {
    public abstract void use();
}

然后创建具体产品类,如 ConcreteProductA 和 ConcreteProductB,它们分别继承自 Product 并实现了其中的抽象方法。

public class ConcreteProductA  extends Product {
    
    @Override
    public void use(){
       System.out.println("use ConcreteProductA");    
    }
}
public class ConcreteProductB  extends Product {
    @Override
    public void use(){
        System.out.println("use ConcreteProductB");     
    }
}

抽象工厂类和具体工厂类

接下来定义一个抽象工厂类  Factory,其中包含一个抽象的工厂方法 createProduct(),用于创建具体的产品对象:

public abstract class Factory {
    public abstract Product createProduct();
}

对于每个具体产品,创建相应的具体工厂类:

public class ConcreteFactoryA extends Factory {
    
    @Override
    public Product createProduct() {
        return new ConcreteProductA();
    }
}
public class ConcreteFactoryB extends Factory {
    
    @Override
    public Product createProduct() {
        return new ConcreteProductB();
    }
}

客户端代码

在客户端代码中,我们可以根据需要选择不同的具体工厂类来创建产品对象。

public class Client {
    public static void main(String[] args) {
        Factory factory = new ConcreteFactoryA();
        Product product = factory.createProduct();
        product.use();
    }
}

通过工厂方法模式,我们将对象的创建过程分散到不同的具体工厂类中,每个具体工厂类只负责创建对应的产品对象。这样可以降低代码的耦合度,同时也方便添加新的产品和工厂。

优点

缺点

注意:工厂方法模式适合复杂对象,而简单对象,特别是只需要通过 new 就可以完成创建的对象,无需使用工厂模式。如果使用工厂模式,就需要引入一个工厂类,会增加系统的复杂度。

简单工厂模式

当只有少量具体产品类时,并且对象的创建逻辑相对简单,没有必要为每个具体产品类创建一个对应的工厂类,此时使用简单工厂模式会更加简洁和直观。

简单工厂模式(Simple Factory Pattern)是工厂方法模式的弱化。

简单工厂模式由三个主要角色组成:

下面是一个简单的示例代码,演示了简单工厂模式的实现:

// 抽象产品类
public interface Animal {
    void speak();
}

// 具体产品类1
public class Cat implements Animal {
    @Override
    public void speak() {
        System.out.println("Meow!");
    }
}

// 具体产品类2
public class Dog implements Animal {
    @Override
    public void speak() {
        System.out.println("Woof!");
    }
}

// 工厂类
public class AnimalFactory {
    public static Animal createAnimal(String type) {
        if (type.equalsIgnoreCase("cat")) {
            return new Cat();
        } else if (type.equalsIgnoreCase("dog")) {
            return new Dog();
        }
        throw new IllegalArgumentException("Invalid animal type: " + type);
    }
}

在上述代码中,我们定义了一个抽象产品类 Animal,并有两个具体产品类 Cat 和 Dog,它们都实现了 Animal 接口。工厂类 AnimalFactory 负责根据客户端传入的参数创建相应的具体产品对象。

使用简单工厂模式,客户端可以通过调用工厂类的静态方法 createAnimal() 来获取所需的具体产品对象。例如:

Animal cat = AnimalFactory.createAnimal("cat");
cat.speak();  // 输出:Meow!

Animal dog = AnimalFactory.createAnimal("dog");
dog.speak();  // 输出:Woof!

简单工厂模式因为工厂类定义了一个静态方法,因此也叫做静态工厂模式。其缺点是工厂类的扩展比较困难,不符合开闭原则,并且随着产品类型增多,简单工厂模式工厂类的代码可能会变得复杂,因此不适用于大规模或复杂的应用程序,但它仍然是一个非常实用的设计模式。

延迟初始化

延迟初始化:一个对象被消费完毕后,并不立刻释放,工厂类保持其初始状态,等待再次被使用。

延迟加载的工厂类,参考代码如下:

public class ProductFactory {
    private static final Map prMap = new HashMap();

    public static synchronized Product createProduct(String type) throws Exception {
        Product product = null;
  //如果Map中已经有这个对象
        if (prMap.containsKey(type)) {
            product = prMap.get(type);
        } else {
            if (type.equals("Product1")) {
                product = new ConcreteProduct1();
            } else {
                product = new ConcreteProduct2();
            }
  //同时把对象放到缓存容器中
            prMap.put(type, product);
        }
        return product;
    }
}

代码算是比较简单,通过定义一个Map容器,容纳所有产生的对象,如果在Map容器中已经有的对象,则直接取出返回;如果没有,则根据需要的类型产生一个对象并放入到Map容器中,以方便下次调用。

这样的好处是可以限制某一个产品类的最大实例化数量,通过判断Map中已有的对象数量来实现。

延迟加载在对象初始化比较复杂的情况下,可以降低对象的产生和销毁带来的复杂性。这是非常有意义的,例如 JDBC 连接数据库,都会要求设置一个 MaxConnections 最大连接数量,该数量就是内存中最大实例化的数量。

总结

工厂方法模式使用的频率非常高,工厂方法模式通过定义抽象工厂类和抽象产品类,将对象的创建委托给子类来实现。它提供了一种灵活、可扩展的对象创建方式,符合开闭原则,并且降低了代码的耦合度。

通过合理地使用工厂方法模式,我们可以提高代码的灵活性、可扩展性和可维护性,从而构建更优秀的软件系统。

来源:Java随想录内容投诉

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

软考中级精品资料免费领

  • 历年真题答案解析
  • 备考技巧名师总结
  • 高频考点精准押题
  • 2024年上半年信息系统项目管理师第二批次真题及答案解析(完整版)

    难度     813人已做
    查看
  • 【考后总结】2024年5月26日信息系统项目管理师第2批次考情分析

    难度     354人已做
    查看
  • 【考后总结】2024年5月25日信息系统项目管理师第1批次考情分析

    难度     318人已做
    查看
  • 2024年上半年软考高项第一、二批次真题考点汇总(完整版)

    难度     435人已做
    查看
  • 2024年上半年系统架构设计师考试综合知识真题

    难度     224人已做
    查看

相关文章

发现更多好内容

猜你喜欢

AI推送时光机
位置:首页-资讯-后端开发
咦!没有更多了?去看看其它编程学习网 内容吧
首页课程
资料下载
问答资讯