Java设计模式之二:简单工厂模式详细解析

一、模式概述

简单工厂模式(Simple Factory Pattern)是一种创建型设计模式,它通过一个工厂类来封装对象的创建过程,而不需要将具体的创建逻辑暴露给客户端。

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

  1. Product(产品接口):定义产品的通用行为,客户端通过该接口与产品进行交互。

  2. ConcreteProduct(具体产品类):实现产品接口,定义具体产品的特定行为。

  3. Factory(工厂类):负责创建产品对象的类,它通常是一个静态方法,在方法中根据传入的参数或逻辑决定创建哪个具体产品的实例,并返回给客户端。

话不多说,直接上代码:

public interface Product {
    void use();
}

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

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

public class ProductFactory {
    public static Product createProduct(String type) {
        if (type.equals("A")) {
            return new ConcreteProductA();
        } else if (type.equals("B")) {
            return new ConcreteProductB();
        }
        
        throw new IllegalArgumentException("Invalid product type: " + type);
    }
}

在这个示例中,Product是产品接口,定义了产品的通用行为。ConcreteProductAConcreteProductB是具体产品类,实现Product接口,并定义了各自的特定行为。

ProductFactory是工厂类,通过静态方法createProduct()创建具体产品的实例。根据传入的参数来判断应该创建哪个具体产品的实例。

二、模式结构组成、实现方式

2.1简单工厂模式的结构

当使用简单工厂模式时,可以通过以下步骤来实现:

  1. 定义产品接口(Product):产品接口定义了产品的通用行为和方法。所有具体产品都必须实现该接口。

  2. 创建具体产品类(ConcreteProduct):具体产品类实现产品接口,并实现具体的产品行为。

  3. 创建工厂类(Factory):工厂类负责根据客户端的请求创建具体的产品对象。通常,工厂类的方法是静态的,以便直接通过类名调用。

2.2简单工厂模式具体示例

下面是一个更详细的示例,演示了如何使用简单工厂模式来创建不同类型的动物:

// 1. 定义产品接口
public interface Animal {
    void sound();
}

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

public class Cat implements Animal {
    @Override
    public void sound() {
        System.out.println("Meow!");
    }
}

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

// 客户端代码
public class Client {
    public static void main(String[] args) {
        Animal dog = AnimalFactory.createAnimal("Dog");
        dog.sound();  // Output: Woof!
        
        Animal cat = AnimalFactory.createAnimal("Cat");
        cat.sound();  // Output: Meow!
    }
}

在这个示例中,我们定义了一个公共的Animal接口,并创建了DogCat两个具体的产品类来实现Animal接口。

工厂类AnimalFactory拥有一个静态方法createAnimal(),根据传入的参数类型来决定创建哪种具体的动物实例。在客户端代码中,我们使用工厂类的静态方法来创建不同类型的动物对象,并执行它们的行为。

2.3简单工厂模式异常处理

当使用简单工厂模式时,还需要考虑如何处理错误情况。在前面的示例中,如果客户端请求创建的产品类型不被支持,工厂方法会抛出IllegalArgumentException。这可能导致客户端需要处理异常情况,这并非总是理想的做法。

一种更好的方法是在工厂类中提供一种默认行为,当客户端请求创建的产品类型不被支持时,返回一个默认的产品对象或者 null。这样客户端代码就不需要显式地处理异常情况。

下面是对工厂类进行修改,添加默认行为:

// 创建工厂类
public class AnimalFactory {
    public static Animal createAnimal(String type) {
        if (type.equals("Dog")) {
            return new Dog();
        } else if (type.equals("Cat")) {
            return new Cat();
        } else {
            System.out.println("Unsupported animal type. Returning default animal.");
            return new DefaultAnimal();
        }
    }
}

在上面的示例中,当客户端请求创建的产品类型不被支持时,工厂方法返回了一个DefaultAnimal对象,这样客户端代码就无需显式处理异常情况。

简单工厂模式为客户端隐藏了实例化产品对象的复杂过程,提供了一个集中的创建点,有助于简化客户端代码和进一步实现封装。但需要注意的是,简单工厂模式最适合具有固定数量产品类型的场景,在产品类型经常变化或需要增加时,维护工厂类的逻辑可能会变得复杂。

三、符合开闭原则的简单工厂模式

3.1什么是开闭原则?

开闭原则是面向对象设计中的一个基本原则,也是SOLID原则中的一部分。它的核心思想是软件实体(如类、模块、函数等)应该对扩展开放,对修改关闭。

具体来说,开闭原则要求设计的软件实体在新增功能时不需要修改原有的代码,而是通过扩展已有的代码来实现。这意味着应该通过接口、抽象类、继承、多态等方式,使得系统具有良好的可扩展性和灵活性。

开闭原则的关键是通过抽象来隔离变化,将变化的部分封装成抽象的接口或基类,使得对于实现的变化可以被独立地扩展,而不影响原有的代码。这样,系统可以很方便地进行功能的扩展和修改,同时又保持了稳定的接口和基础架构。

开闭原则具有以下优点:

  1. 可维护性:由于对现有代码的修改被限制在扩展的部分,所以系统的维护变得更加容易和安全。

  2. 可扩展性:通过扩展接口或基类,可以方便地添加新的功能,满足不同的需求。

  3. 可复用性:由于对现有代码的修改最小化,所以可以更好地复用原有的模块和功能。

遵循开闭原则可以使软件系统更稳定、可维护、可扩展,并能够适应变化和需求的不断演变。在实际开发中,我们通常通过使用设计模式、依赖倒置原则等方法来实现开闭原则。

3.2简单工厂模式模拟手机工厂

某手机工厂专为各知名手机品牌代工生产各类手机,当需要苹果手机时只需要在调用该工厂的工厂方法时传人参数 iPhone,需要华为手机时只需要传人参数Huawei,工厂可以根据传入的不同参数返回不同品牌的手机。现使用简单工厂模式来模拟该工厂的生产过程。

以下是具体代码:

public interface Mobile {
    public void work();
}



public class iPhone implements Mobile {
    @Override
    public void work() {
        System.out.println("使用苹果手机");
    }
}



public class Huawei implements Mobile {
    @Override
    public void work() {
        System.out.println("使用华为手机");
    }
}






/*
* MobileFactory 是工厂类,它是整个系统的核心,
* 它提供了静态工厂方法 produceMobile(),工厂方法中包含一个字符串类型的参数,
* 在内部业务逻辑中根据参数值的不同实例化不同的具体产品类,返回相应的对象。
* */
public class MobileFactory {
    public static Mobile produceMobile(String brand) throws Exception {
        if (brand.equals("iPhone")) {
            System.out.println("工厂生产苹果手机");
            return new iPhone();
        } else if (brand.equals("Huawei")) {
            System.out.println("工厂生产华为手机");
            return new Huawei();
        } else {
            throw new Exception("暂无该品牌手机");
        }
    }
}



/*
* 在此引入了一个工具类——XMLUtilTV,通过它可以从 XMIL格式的配置文件中读取节点获取数据,
* 如品牌名称等信息,如果需要修改品牌名称,无须修改客户端代码,只需修改配置文件。
* 通过配置文件可以极大提高系统的扩展性,让软件实体更符合开闭原则。
* */

public class XMLUtilMobile {
    public static String getBrandName() {
        try {
            DocumentBuilderFactory dBFactory = DocumentBuilderFactory.newInstance();
            DocumentBuilder builder = dBFactory.newDocumentBuilder();
            Document document;
            document =builder.parse(new File("configMobile.xml"));
            NodeList nl = document.getElementsByTagName("brandName");
            Node classNode = nl.item(0).getFirstChild();
            String brandName = classNode.getNodeValue().trim();
            return brandName;
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }
}





public class Client {
    public static void main(String[] args) {
        try {
            Mobile mobile;
            String brandName = XMLUtilMobile.getBrandName();
            mobile = MobileFactory.produceMobile(brandName);
            mobile.work();
        } catch (Exception e) {
            System.out.println(e.getMessage());
        }
    }
}


    
        iPhone
    

如果需要更换手机品牌,无须修改客户端代码及类库代码,只需要修改配置文件即可,提高了系统的灵活性。如果需要增加新类型的手机,即增加新的具体产品类,则需要修改工厂类,这在一定程度上违反了开闭原则,但是无须修改客户端测试类,这就带来一定程度的灵活性。
 

四、简单工厂模式优缺点

1.简单工厂模式的优点

(1)工厂类含有必要的判断逻辑,可以决定在什么时候创建哪一个产品类的实例,客户端可以免除直接创建产品对象的责任,而仅仅“消费”产品;简单工厂模式通过这种做法实现了对责任的分割,它提供了专门的工厂类用于创建对象。
(2)客户端无须知道所创建的具体产品类的类名,只需要知道具体产品类所对应的参数即可,对于一些复杂的类名,通过简单工厂模式可以减少使用者的记忆量。
(3)通过引入配置文件,可以在不修改任何客户端代码的情况下更换和增加新的具体产品类,在一定程度上提高了系统的灵活性。
 

2.简单工厂模式的缺点


(1)由于工厂类集中了所有产品创建逻辑,一旦不能正常工作,整个系统都要受到影响。
(2) 使用简单工厂模式将会增加系统中类的个数,在一定程度上增加了系统的复杂度和理解难度。
(3)系统扩展困难,一旦添加新产品就不得不修改工厂逻辑,在产品类型较多时,有可能造成工厂逻辑过于复杂,不利于系统的扩展和维护。
(4)简单工厂模式由于使用了静态工厂方法,造成工厂角色无法形成基于继承的等级结构。

你可能感兴趣的:(java,设计模式,简单工厂模式,后端)