Java 设计模式(创建型)

文章目录

工厂模式

工厂模式(Factory Pattern)是一种创建型设计模式,用于创建对象的接口,但是由子类决定要实例化的类是哪一个。它提供了一种将对象的实例化过程封装起来的方法,从而使得客户端代码与具体创建对象的类解耦。

  • 结构

    1. 抽象产品(Product):定义了产品的接口或抽象类,通常是工厂所创建的对象的共同基类。
    2. 具体产品(Concrete Product):实现了抽象产品接口或继承了抽象产品类,是工厂模式所创建的具体对象。
    3. 抽象工厂(Factory):声明了工厂方法(Factory Method),用于创建抽象产品的接口或抽象类。
    4. 具体工厂(Concrete Factory):实现了抽象工厂接口或继承了抽象工厂类,负责创建具体产品的对象。
    5. 客户端(Client):使用工厂对象创建具体产品对象的类。
  • 场景

    1. 对象的创建需要复杂逻辑:当对象的创建过程比较复杂或者需要根据不同条件创建不同的对象时,工厂模式可以将创建过程封装起来,提供一个统一的接口。
    2. 需要解耦对象的使用和创建:当需要在客户端代码中解耦对象的使用和创建时,工厂模式是一个不错的选择,客户端只需要知道工厂接口或抽象类,而不需要关心具体的实现细节。
    3. 需要动态切换产品族:工厂模式可以根据需要动态地选择产品族,比如根据用户的地区或语言选择不同的产品。
  • 优点

    1. 解耦:工厂模式将客户端代码与具体的创建逻辑分离,客户端只需要知道工厂接口或抽象类,不需要关心具体的实现细节,从而降低了耦合度。
    2. 封装性:工厂模式将对象的创建过程封装在工厂类中,使得客户端无需知道创建对象的细节,同时也隐藏了创建对象的具体实现。
    3. 可扩展性:通过添加新的具体工厂类,可以很容易地向系统中添加新的产品,而不需要修改已有的代码。
  • 缺点

    1. 类的数量增加:每个具体产品都需要对应一个具体工厂类,可能会导致类的数量增加,从而增加了系统的复杂性。
    2. 不适合复杂对象的创建:当创建对象的过程比较复杂或者需要初始化大量的参数时,工厂模式可能会变得笨重,并且不够灵活。
  • 示例

java 复制代码
// 抽象产品:手机
interface Phone {
    void call();
}

// 具体产品:小米手机
class Xiaomi implements Phone {
    @Override
    public void call() {
        System.out.println("使用小米手机打电话");
    }
}

// 具体产品:华为手机
class Huawei implements Phone {
    @Override
    public void call() {
        System.out.println("使用华为手机打电话");
    }
}

// 抽象工厂:手机工厂
interface PhoneFactory {
    Phone createPhone();
}

// 具体工厂:小米手机工厂
class XiaomiFactory implements PhoneFactory {
    @Override
    public Phone createPhone() {
        return new Xiaomi();
    }
}

// 具体工厂:华为手机工厂
class HuaweiFactory implements PhoneFactory {
    @Override
    public Phone createPhone() {
        return new Huawei();
    }
}

// 客户端代码
public class Main {
    public static void main(String[] args) {
        // 创建小米手机
        PhoneFactory xiaomiFactory = new XiaomiFactory();
        Phone xiaomiPhone = xiaomiFactory.createPhone();
        xiaomiPhone.call();

        // 创建华为手机
        PhoneFactory huaweiFactory = new HuaweiFactory();
        Phone huaweiPhone = huaweiFactory.createPhone();
        huaweiPhone.call();
    }
}
  • 输出结果
bash 复制代码
使用小米手机打电话
使用华为手机打电话

单例模式

单例模式(Singleton Pattern)是一种创建型设计模式,旨在确保类只有一个实例,并提供全局访问点。

  • 结构

    1. 私有构造函数:确保其他类无法通过构造函数创建实例。
    2. 静态变量:在类内部创建一个私有静态变量来保存单例实例。
    3. 静态方法:提供一个静态方法来获取单例实例,如果实例不存在,则在此方法内部创建实例并返回。
  • 场景

    1. 资源管理器:例如线程池、数据库连接池等资源管理器常常使用单例模式,以确保全局只有一个资源管理器实例。
    2. 配置管理器:应用程序的配置管理器通常以单例模式实现,以确保全局只有一个配置管理器实例。
    3. 日志记录器:日志记录器通常以单例模式实现,以确保在应用程序中的任何位置都可以轻松访问和使用日志记录功能。
    4. 窗口管理器:图形用户界面(GUI)应用程序中的窗口管理器通常以单例模式实现,以确保全局只有一个窗口管理器实例来管理所有窗口。
  • 优点

    1. 全局唯一性:确保一个类只有一个实例,全局范围内提供该实例的访问点。
    2. 延迟实例化:单例对象通常在首次被请求时才被实例化,从而节省了系统资源。
    3. 简化访问:通过全局访问点,简化了对单例对象的访问和管理。
  • 缺点

    1. 可能引起性能问题:在高并发情况下,单例模式可能成为性能瓶颈,因为所有线程都必须等待获取单例对象。
    2. 可能引起线程安全问题:如果没有正确地实现线程安全措施,可能会导致多线程环境下出现多个实例。
  • 示例1

java 复制代码
class Singleton {
    // 使用 volatile 关键字确保 instance 在多线程环境下的可见性
    private static volatile Singleton instance;

    // 私有构造函数,防止外部通过构造函数创建实例
    private Singleton() {
    }

    // 提供全局访问点获取唯一实例
    public static Singleton getInstance() {
        // 双重检查锁定,提高效率并确保线程安全
        if (instance == null) {
            synchronized (Singleton.class) {
                if (instance == null) {
                    instance = new Singleton();
                }
            }
        }
        return instance;
    }

    // 示例方法
    public void exampleMethod() {
        System.out.println("这是单例模式中的示例方法。");
    }
}

// 客户端代码
public class Main {
    public static void main(String[] args) {
        // 获取单例实例
        Singleton singleton = Singleton.getInstance();

        // 调用示例方法
        singleton.exampleMethod();
    }
}
  • 输出结果
bash 复制代码
这是单例模式中的示例方法。
  • 示例2
java 复制代码
class ConfigurationManager {
    // 私有静态变量保存唯一实例
    private static ConfigurationManager instance;

    // 私有构造函数,防止外部通过构造函数创建实例
    private ConfigurationManager() {
        // 在这里可以进行配置的初始化工作
        System.out.println("配置管理器初始化完成。");
    }

    // 提供全局访问点获取唯一实例
    public static ConfigurationManager getInstance() {
        // 懒汉式单例模式实现,第一次调用时才实例化对象
        if (instance == null) {
            instance = new ConfigurationManager();
        }
        return instance;
    }

    // 示例方法:获取配置项
    public String getConfig(String key) {
        // 这里可以根据 key 获取相应的配置项
        return "配置项:" + key;
    }
}

// 客户端代码
public class Main {
    public static void main(String[] args) {
        // 获取配置管理器实例
        ConfigurationManager configManager = ConfigurationManager.getInstance();

        // 使用配置管理器获取配置项
        String configValue = configManager.getConfig("database.url");
        System.out.println(configValue);
    }
}
  • 输出结果
bash 复制代码
配置管理器初始化完成。
配置项:database.url

抽象工厂模式

抽象工厂模式(Abstract Factory Pattern)是一种创建型设计模式,它提供了一种创建一系列相关或相互依赖对象的接口,而无需指定它们具体的类。它属于工厂模式的一种扩展,通过提供一个抽象工厂接口,可以创建一组相关的产品对象,而不是单个产品。

  • 结构

    1. 抽象工厂接口:定义了创建一组相关产品对象的方法,每个方法对应一个产品。
    2. 具体工厂类:实现了抽象工厂接口,负责创建具体的产品对象。
    3. 抽象产品接口:定义了产品对象的接口,每个具体产品类都实现了该接口。
    4. 具体产品类:实现了抽象产品接口,代表了具体的产品对象。
  • 场景

    1. 跨平台产品:抽象工厂模式可以用于创建跨平台产品,比如同时在 Windows 和 macOS 上创建应用程序,每个平台都有自己的按钮、文本框等 UI 组件。
    2. 产品族:抽象工厂模式适用于需要一次性创建一系列相关或相互依赖的产品对象的场景,比如创建一个汽车工厂,可以生产不同品牌的汽车,每个品牌又包括不同型号的车型。
    3. 数据库访问:在数据库访问中,抽象工厂模式可以用于创建不同类型的数据库连接、命令和数据读取器,以适应不同数据库的需求。
  • 优点

    1. 封装性:抽象工厂模式将产品的创建过程封装在工厂类中,客户端不需要知道具体的创建细节,只需要通过工厂接口来创建产品。
    2. 灵活性:可以在运行时动态切换具体工厂类,从而创建不同系列的产品对象,满足不同的需求。
    3. 易于扩展:增加新的具体工厂和产品类非常容易,无需修改现有代码,符合开闭原则。
  • 缺点

    1. 复杂性:随着产品系列的增加,抽象工厂模式的类数量会增加,导致系统复杂度增加。
    2. 耦合性:抽象工厂模式中各个具体工厂类与具体产品类之间存在一定的耦合性,增加了系统的耦合度。
  • 示例

java 复制代码
// 抽象产品接口:按钮
interface Button {
    void display();
}

// 具体产品:Spring按钮
class SpringButton implements Button {
    @Override
    public void display() {
        System.out.println("显示浅绿色按钮");
    }
}

// 具体产品:Summer按钮
class SummerButton implements Button {
    @Override
    public void display() {
        System.out.println("显示浅蓝色按钮");
    }
}

// 抽象产品接口:文本框
interface TextField {
    void display();
}

// 具体产品:Spring文本框
class SpringTextField implements TextField {
    @Override
    public void display() {
        System.out.println("显示浅绿色文本框");
    }
}

// 具体产品:Summer文本框
class SummerTextField implements TextField {
    @Override
    public void display() {
        System.out.println("显示浅蓝色文本框");
    }
}

// 抽象工厂接口
interface SkinFactory {
    Button createButton();
    TextField createTextField();
}

// 具体工厂:Spring皮肤工厂
class SpringSkinFactory implements SkinFactory {
    @Override
    public Button createButton() {
        return new SpringButton();
    }

    @Override
    public TextField createTextField() {
        return new SpringTextField();
    }
}

// 具体工厂:Summer皮肤工厂
class SummerSkinFactory implements SkinFactory {
    @Override
    public Button createButton() {
        return new SummerButton();
    }

    @Override
    public TextField createTextField() {
        return new SummerTextField();
    }
}

// 客户端
public class Client {
    public static void main(String[] args) {
        // 创建Spring皮肤工厂
        SkinFactory springFactory = new SpringSkinFactory();
        // 创建Spring按钮
        Button springButton = springFactory.createButton();
        // 显示Spring按钮
        springButton.display();
        // 创建Spring文本框
        TextField springTextField = springFactory.createTextField();
        // 显示Spring文本框
        springTextField.display();

        // 创建Summer皮肤工厂
        SkinFactory summerFactory = new SummerSkinFactory();
        // 创建Summer按钮
        Button summerButton = summerFactory.createButton();
        // 显示Summer按钮
        summerButton.display();
        // 创建Summer文本框
        TextField summerTextField = summerFactory.createTextField();
        // 显示Summer文本框
        summerTextField.display();
    }
}
  • 输出结果
bash 复制代码
显示浅绿色按钮
显示浅绿色文本框
显示浅蓝色按钮
显示浅蓝色文本框

建造者模式

建造者模式是一种创建型设计模式,它将一个复杂对象的构建过程和其表示分离开来,从而可以使同样的构建过程可以创建不同的表示。建造者模式的关键是将构建过程分解成多个步骤,并提供一个指导者(Director)来组织这些步骤的执行,以构建出不同的对象表示。

  • 结构

    1. 产品(Product):表示被构建的复杂对象。产品类通常包含多个部件,如汽车对象可能包含引擎、车轮、座椅等部件。
    2. 抽象建造者(Builder):定义了构建产品各个部件的抽象方法,并提供了一个用于返回最终产品的方法。抽象建造者通常是一个接口或者抽象类。
    3. 具体建造者(Concrete Builder):实现了抽象建造者接口,负责构建产品的各个部件,并实现了返回最终产品的方法。
    4. 指导者(Director):负责组织构建过程,根据具体的构建者来指导构建过程的顺序和方法,最终构建出产品。
  • 场景

    1. 需要构建复杂对象:当需要构建复杂对象,且构建过程比较复杂时,可以使用建造者模式。
    2. 需要构建多个表示:当需要通过同样的构建过程创建不同的表示时,可以使用建造者模式。
  • 优点

    1. 分离构建过程和表示:建造者模式将构建过程和最终产品的表示分离开来,使得可以灵活地组合构建过程和表示。
    2. 复用性:建造者模式可以通过不同的建造者来创建不同的产品,提高了代码的复用性。
    3. 更好的封装性:建造者模式将产品的构建过程封装在具体建造者中,使得客户端无需了解产品的具体构建过程。
  • 缺点

    1. 增加了代码量:建造者模式引入了多个新的类,可能会增加系统的复杂性和代码量。
    2. 不适合构建较简单的对象:当产品对象较简单,且构建过程相对固定时,使用建造者模式可能会显得繁琐。
  • 示例

java 复制代码
// 产品类 - 汽车
class Car {
    private String brand; // 品牌
    private String model; // 型号
    private String color; // 颜色
    
    public Car(String brand, String model, String color) {
        this.brand = brand;
        this.model = model;
        this.color = color;
    }
    
    public String getBrand() {
        return brand;
    }
    
    public String getModel() {
        return model;
    }
    
    public String getColor() {
        return color;
    }
    
    @Override
    public String toString() {
        return "Car{" +
                "brand='" + brand + '\'' +
                ", model='" + model + '\'' +
                ", color='" + color + '\'' +
                '}';
    }
}

// 抽象建造者接口
interface CarBuilder {
    void buildBrand(String brand); // 建造品牌
    void buildModel(String model); // 建造型号
    void buildColor(String color); // 建造颜色
    Car getResult(); // 获取结果
}

// 具体建造者 - 奥迪汽车建造者
class AudiCarBuilder implements CarBuilder {
    private Car car;
    
    public AudiCarBuilder() {
        car = new Car("Audi", "", "");
    }
    
    @Override
    public void buildBrand(String brand) {
        car = new Car("Audi", "", "");
    }
    
    @Override
    public void buildModel(String model) {
        car = new Car(car.getBrand(), model, "");
    }
    
    @Override
    public void buildColor(String color) {
        car = new Car(car.getBrand(), car.getModel(), color);
    }
    
    @Override
    public Car getResult() {
        return car;
    }
}

// 指导者 - 汽车销售员
class CarSalesman {
    private CarBuilder carBuilder;
    
    public void setCarBuilder(CarBuilder carBuilder) {
        this.carBuilder = carBuilder;
    }
    
    public Car constructCar() {
        carBuilder.buildBrand("Audi"); // 建造品牌
        carBuilder.buildModel("A4"); // 建造型号
        carBuilder.buildColor("Black"); // 建造颜色
        return carBuilder.getResult(); // 获取结果
    }
}

public class BuilderPatternExample {
    public static void main(String[] args) {
        CarBuilder audiCarBuilder = new AudiCarBuilder();
        CarSalesman carSalesman = new CarSalesman();
        carSalesman.setCarBuilder(audiCarBuilder);
        
        Car car = carSalesman.constructCar();
        System.out.println(car);
    }
}
  • 输出结果
bash 复制代码
Car{brand='Audi', model='A4', color='Black'}

原型模式

原型模式(Prototype Pattern)是一种创建型设计模式,它用于创建对象的克隆,而不是通过实例化来创建新对象。原型模式通过复制现有对象来创建新对象,从而避免了耗时的实例化过程。

  • 结构

    1. 原型接口:定义了一个可以克隆自身的方法。
    2. 具体原型类:实现了原型接口,提供了克隆自身的方法。
    3. 客户端:通过调用具体原型类的克隆方法来获取新的对象。
  • 场景

    1. 对象初始化成本高:当对象的创建过程比较耗时或资源消耗较大时,可以使用原型模式提前创建好对象,然后通过复制来避免重复初始化。
    2. 对象类型不确定:当需要在运行时动态地创建对象,并且不清楚对象的具体类型时,可以使用原型模式。
    3. 复杂对象的复制:当对象包含了其他对象的引用,且需要进行深层次的拷贝时,可以使用原型模式来实现对象的复制。
    4. 保护对象的状态:当需要保护对象的状态不被外部修改时,可以通过克隆来获取对象的副本,从而保护原始对象的状态。
  • 优点

    1. 减少资源消耗:通过复制现有对象来创建新对象,避免了耗时的实例化过程,减少了资源消耗。
    2. 简化对象创建:可以在运行时动态地创建对象,而无需事先知道对象的类型。
    3. 灵活性:可以通过修改原型对象来创建不同类型的对象,或者通过克隆对象来创建多个相似对象。
  • 缺点

    1. 深拷贝问题:原型模式要求对象支持克隆操作,但如果对象中包含了其他对象的引用,克隆操作可能会导致深层次的拷贝问题。
    2. 复杂性:如果对象的复制过程比较复杂,可能会导致代码复杂度增加。
  • 示例

java 复制代码
// 实现Cloneable接口,表示可以被克隆
class Shape implements Cloneable {
    private String type;

    public String getType() {
        return type;
    }

    public void setType(String type) {
        this.type = type;
    }

    // 重写Object类的clone方法,实现浅拷贝
    @Override
    public Object clone() throws CloneNotSupportedException {
        return super.clone();
    }
}

// 具体原型类:圆形
class Circle extends Shape {
    public Circle() {
        setType("圆形");
    }
}

// 具体原型类:正方形
class Square extends Shape {
    public Square() {
        setType("正方形");
    }
}

// 客户端
public class Client {
    public static void main(String[] args) {
        // 创建圆形对象
        Circle circle = new Circle();
        try {
            // 克隆圆形对象
            Circle clonedCircle = (Circle) circle.clone();
            System.out.println("原型对象:" + circle.getType());
            System.out.println("克隆对象:" + clonedCircle.getType());
        } catch (CloneNotSupportedException e) {
            e.printStackTrace();
        }

        // 创建正方形对象
        Square square = new Square();
        try {
            // 克隆正方形对象
            Square clonedSquare = (Square) square.clone();
            System.out.println("原型对象:" + square.getType());
            System.out.println("克隆对象:" + clonedSquare.getType());
        } catch (CloneNotSupportedException e) {
            e.printStackTrace();
        }
    }
}
  • 输出结果
bash 复制代码
原型对象:圆形
克隆对象:圆形
原型对象:正方形
克隆对象:正方形
相关推荐
湫ccc1 小时前
《Python基础》之字符串格式化输出
开发语言·python
弗拉唐1 小时前
springBoot,mp,ssm整合案例
java·spring boot·mybatis
oi771 小时前
使用itextpdf进行pdf模版填充中文文本时部分字不显示问题
java·服务器
mqiqe1 小时前
Python MySQL通过Binlog 获取变更记录 恢复数据
开发语言·python·mysql
AttackingLin2 小时前
2024强网杯--babyheap house of apple2解法
linux·开发语言·python
少说多做3432 小时前
Android 不同情况下使用 runOnUiThread
android·java
知兀2 小时前
Java的方法、基本和引用数据类型
java·笔记·黑马程序员
蓝黑20202 小时前
IntelliJ IDEA常用快捷键
java·ide·intellij-idea