Java 23种设计模式介绍以及代码示例 第一篇创建型设计模式

简介: 代码组织和可读性:创建型设计模式提供了一种结构化的方式来组织代码,使得代码更加清晰、易读。它们定义了对象的创建和使用的规范,从而使代码逻辑更加明确,易于理解和维护。2. 对象创建的灵活性和可扩展性:创建型设计模式将对象创建的过程抽象出来,通过使用相应的模式,可以在不修改现有代码的情况下,改变对象的创建方式或者增加新的对象创建方式。这提供了一定的灵活性和可扩展性,使得系统更易于扩展和维护。

设计模式

一,介绍

20200721164830114.png

1.为什么要使用设计模式

1. 代码组织和可读性:创建型设计模式提供了一种结构化的方式来组织代码,使得代码更加清晰、易读。它们定义了对象的创建和使用的规范,从而使代码逻辑更加明确,易于理解和维护。

2. 对象创建的灵活性和可扩展性:创建型设计模式将对象创建的过程抽象出来,通过使用相应的模式,可以在不修改现有代码的情况下,改变对象的创建方式或者增加新的对象创建方式。这提供了一定的灵活性和可扩展性,使得系统更易于扩展和维护。

3. 降低耦合度:创建型设计模式可以降低对象之间的耦合度。它们将对象的创建过程封装在一个单独的地方,使得对象之间的依赖关系减少到最小。这样,当需要更改某个具体类时,只需更改一个地方,而不必修改整个系统的代码。

4. 代码重用:创建型设计模式可以促进代码的重用。通过使用工厂模式、原型模式等,可以复用已有的对象实例或者创建新的对象实例,避免了重复的对象创建过程。这样可以提高代码的效率和性能。

5. 符合设计原则:创建型设计模式通常符合面向对象设计原则,如单一职责原则、开闭原则、依赖倒置原则等。它们强调将对象的创建和使用进行解耦,并提供了一种灵活的方式来管理对象的创建过程,使得系统更加可维护、可扩展。

总之,使用创建型设计模式可以帮助我们更好地组织和管理对象的创建过程,提高代码的可读性、可维护性和可扩展性。它们为我们提供了一些通用的解决方案,使得我们能够更加灵活地创建和使用对象,同时降低代码的耦合度,增强代码的可复用性和可扩展性。

2.创建型设计模式介绍

当我们在设计Java应用程序时,经常会遇到需要创建对象的情况。创建型设计模式提供了一些通用的解决方案,帮助我们更好地组织和管理对象的创建过程,并提供灵活性和可扩展性

1. 单例模式(Singleton Pattern):

  单例模式确保一个类只有一个实例,并提供全局访问点。该模式常用于需要共享资源、控制资源访问、或限制某个类只能有一个实例的场景。

2. 简单工厂模式(Simple Factory Pattern):

  简单工厂模式通过一个工厂类根据特定参数来创建对象。使用简单工厂模式可以将对象的创建和使用分离,降低耦合度,使代码更具扩展性。

3. 工厂方法模式(Factory Method Pattern):

  工厂方法模式定义一个创建对象的接口,由子类决定实例化哪个类。与简单工厂模式不同的是,工厂方法模式将对象的实例化交给了子类,使得系统更加灵活,符合开闭原则。

4. 抽象工厂模式(Abstract Factory Pattern):

  抽象工厂模式提供一个接口用于创建相关或依赖对象的系列,而无需指定具体类。它隔离了具体类的实现细节,使得客户端可以与具体类的实例化过程解耦。

5. 原型模式(Prototype Pattern):

  原型模式通过复制现有对象来创建新的对象。它通过克隆或复制的方式来创建对象,避免了类似于new操作的开销,并且可以更加灵活地生成对象。

6. 建造者模式(Builder Pattern):

  建造者模式将一个复杂对象的构建过程和它的表示分离,使得同样的构建过程可以创建不同的表示。它将对象的构建步骤逐步细化,以创建复杂对象。

这些创建型设计模式都有各自的特点和适用场景,我们可以根据具体的需求选择合适的模式来创建对象。使用这些模式可以提高代码的可维护性、可读性和可扩展性,同时降低耦合度,增强代码的灵活性。

二,单例模式

在中,单例模式常见的实现方式有以下几种:

1. 饿汉式(Eager Initialization):

public class Singleton {
    private static final Singleton INSTANCE = new Singleton(); // 在类加载时就创建实例,并在静态变量中进行初始化
    private Singleton() {} // 私有构造方法
    public static Singleton getInstance() {
        return INSTANCE; // 提供全局访问点
    }
}

image.gif

2. 懒汉式(Lazy Initialization):

public class Singleton {
    private static Singleton instance; // 延迟创建实例,在需要时才进行初始化
    private Singleton() {} // 私有构造方法
    public static synchronized Singleton getInstance() { // 使用同步锁确保线程安全
        if (instance == null) {
            instance = new Singleton();
        }
        return instance; // 提供全局访问点
    }
}

image.gif

3. 静态内部类方式(Static Inner Class):

public class Singleton {
    private Singleton() {} // 私有构造方法
    private static class SingletonHolder {
        private static final Singleton INSTANCE = new Singleton(); // 嵌套的静态类实现延迟加载,并利用类加载机制保证线程安全
    }
    public static Singleton getInstance() {
        return SingletonHolder.INSTANCE; // 提供全局访问点
    }
}

image.gif

4. 枚举方式(Enum):

public enum Singleton {
    INSTANCE; // 利用枚举类型的特性,保证实例的唯一性和线程安全
    // 可以添加其他方法和属性
    public void doSomething() {}
}

image.gif

5.双重检查锁(Double-Checked Locking)

 

public class Singleton {
  // 双重检查锁是一种延迟初始化的单例模式实现方式,可以在多线程环境下提供高性能和线程安全。
  private volatile static Singleton instance; // 使用volatile关键字确保可见性和禁止指令重排序
    private Singleton() {} // 私有构造方法
    public static Singleton getInstance() {
        if (instance == null) { // 第一次检查,避免不必要的同步
            synchronized (Singleton.class) { // 加锁确保线程安全
                if (instance == null) { // 第二次检查,防止多个线程同时通过第一次检查
                    instance = new Singleton();
                }
            }
        }
        return instance; // 提供全局访问点
    }
}

image.gif

双重检查锁模式中,使用两次判断实例是否为null,第一次判断避免不必要的同步,第二次判断在加锁的情况下确保只有一个线程创建实例。同时,使用`volatile`关键字修饰`instance`变量,确保可见性和禁止指令重排序,避免可能出现的线程安全问题。

需要注意的是,双重检查锁模式需要在JDK 1.5及以上版本才能正常工作,且在早期的JDK版本中可能存在双重检查锁失效的问题,可以通过添加`volatile`关键字和使用内部静态类等方式解决。因此,在选择使用双重检查锁模式时,需要仔细考虑平台的兼容性和实现的正确性。

三,工厂方法模式

1.工厂方法模式(Factory Method Pattern)

是一种创建型设计模式,它提供了一种将对象的创建逻辑封装在工厂类中的方式,从而使得客户端代码与具体产品类解耦。

工厂方法模式中包含以下角色:

- 抽象产品(Abstract Product):定义具体产品的公共接口。

- 具体产品(Concrete Product):具体实现抽象产品接口的产品类。

- 抽象工厂(Abstract Factory):定义创建抽象产品的方法。

- 具体工厂(Concrete Factory):实现抽象工厂接口,负责创建具体产品。

下面是一个简单的示例,演示了工厂方法模式在Java中的实现:

// 抽象产品接口
public interface Product {
    void doSomething();
}
// 具体产品A
public class ConcreteProductA implements Product {
    @Override
    public void doSomething() {
        System.out.println("Product A doing something.");
    }
}
// 具体产品B
public class ConcreteProductB implements Product {
    @Override
    public void doSomething() {
        System.out.println("Product B doing something.");
    }
}
// 抽象工厂接口
public interface Factory {
    Product createProduct();
}
// 具体工厂A
public class ConcreteFactoryA implements Factory {
    @Override
    public Product createProduct() {
        return new ConcreteProductA();
    }
}
// 具体工厂B
public class ConcreteFactoryB implements Factory {
    @Override
    public Product createProduct() {
        return new ConcreteProductB();
    }
}
// 客户端代码
public class Client {
    public static void main(String[] args) {
        Factory factoryA = new ConcreteFactoryA();
        Product productA = factoryA.createProduct();
        productA.doSomething();
        Factory factoryB = new ConcreteFactoryB();
        Product productB = factoryB.createProduct();
        productB.doSomething();
    }
}

image.gif

在上述示例中,抽象产品接口`Product`定义了产品的公共方法`doSomething`,具体产品类`ConcreteProductA`和`ConcreteProductB`实现了抽象产品接口。

抽象工厂接口`Factory`定义了创建产品的方法`createProduct`,具体工厂类`ConcreteFactoryA`和`ConcreteFactoryB`实现了抽象工厂接口,分别负责创建具体产品`ConcreteProductA`和`ConcreteProductB`。

客户端代码通过具体工厂来创建具体产品对象,并调用其方法。使用工厂方法模式,客户端与具体产品类解耦,可以方便地替换具体工厂和具体产品,扩展新的产品族也更加容易。

注意,工厂方法模式适用于需要扩展产品族的情况,如果只需创建单一产品,可以考虑使用简单工厂模式。

四,抽象工厂模式

1.介绍

抽象工厂模式可以看作是工厂方法模式的扩展。工厂方法模式只能创建单个产品族中的产品对象,而抽象工厂模式则可以创建多个产品族中的产品对象。

在工厂方法模式中,我们定义了一个抽象的工厂接口,具体的工厂类实现了这个接口,分别负责创建属于自己产品线的产品对象。每个产品对象也都需要实现对应的抽象产品接口。客户端代码通过工厂接口调用具体的工厂类来获得所需的产品对象。

在抽象工厂模式中,我们定义了一个抽象工厂接口,具体的工厂类同样实现这个接口,不同的是,每个工厂类负责创建多个产品族中的产品对象。也就是说,每个工厂类不仅要定义生产一种产品的抽象方法,还会定义生产不同产品族的抽象方法。同样地,每个产品对象都需要实现对应的抽象产品接口。

在抽象工厂模式中,客户端代码通过具体的工厂类来获得所需的产品对象,通常情况下,客户端代码只需要持有一个符合抽象工厂接口的引用,就可以使用不同子类实现产生的具体工厂对象来创建不同产品族的具体产品对象。

抽象工厂模式与工厂方法模式相比,最大的不同点是抽象工厂模式中支持多个不同的产品族,而工厂方法模式只支持一个产品族。此外,在实现上,抽象工厂模式需要定义更多的抽象类和接口,增加了代码量,但同时也让系统的可扩展性和可维护性更好。

2.代码Demo

抽象工厂模式(Abstract Factory Pattern)是一种创建型设计模式,它提供了一种将相关产品对象组合成产品族的方式,而无需指定具体的类。

抽象工厂模式中包含以下角色:

- 抽象工厂(Abstract Factory):定义创建一组产品的方法。

- 具体工厂(Concrete Factory):实现抽象工厂接口,负责创建具体产品。

- 抽象产品(Abstract Product):定义一组产品的公共接口。

- 具体产品(Concrete Product):具体实现抽象产品接口的产品类。

下面是一个简单的示例,演示了抽象工厂模式在Java中的实现:

// 抽象产品A
public interface AbstractProductA {
    void doSomething();
}
// 具体产品A1
public class ConcreteProductA1 implements AbstractProductA {
    @Override
    public void doSomething() {
        System.out.println("Product A1 doing something.");
    }
}
// 具体产品A2
public class ConcreteProductA2 implements AbstractProductA {
    @Override
    public void doSomething() {
        System.out.println("Product A2 doing something.");
    }
}
// 抽象产品B
public interface AbstractProductB {
    void doAnotherThing();
}
// 具体产品B1
public class ConcreteProductB1 implements AbstractProductB {
    @Override
    public void doAnotherThing() {
        System.out.println("Product B1 doing another thing.");
    }
}
// 具体产品B2
public class ConcreteProductB2 implements AbstractProductB {
    @Override
    public void doAnotherThing() {
        System.out.println("Product B2 doing another thing.");
    }
}
// 抽象工厂接口
public interface AbstractFactory {
    AbstractProductA createProductA();
    AbstractProductB createProductB();
}
// 具体工厂1
public class ConcreteFactory1 implements AbstractFactory {
    @Override
    public AbstractProductA createProductA() {
        return new ConcreteProductA1();
    }
    @Override
    public AbstractProductB createProductB() {
        return new ConcreteProductB1();
    }
}
// 具体工厂2
public class ConcreteFactory2 implements AbstractFactory {
    @Override
    public AbstractProductA createProductA() {
        return new ConcreteProductA2();
    }
    @Override
    public AbstractProductB createProductB() {
        return new ConcreteProductB2();
    }
}
// 客户端代码
public class Client {
    public static void main(String[] args) {
        AbstractFactory factory1 = new ConcreteFactory1();
        AbstractProductA productA1 = factory1.createProductA();
        AbstractProductB productB1 = factory1.createProductB();
        productA1.doSomething();
        productB1.doAnotherThing();
        AbstractFactory factory2 = new ConcreteFactory2();
        AbstractProductA productA2 = factory2.createProductA();
        AbstractProductB productB2 = factory2.createProductB();
        productA2.doSomething();
        productB2.doAnotherThing();
    }
}

image.gif

在上述示例中,抽象工厂接口`AbstractFactory`定义了创建一组产品的方法,抽象产品接口`AbstractProductA`和`AbstractProductB`分别定义了一组产品的公共接口,具体产品类`ConcreteProductA1`、`ConcreteProductA2`、`ConcreteProductB1`和`ConcreteProductB2`实现了抽象产品接口。

具体工厂类`ConcreteFactory1`和`ConcreteFactory2`实现了抽象工厂接口,分别负责创建具体产品族,其中`ConcreteFactory1`创建的产品族由`ConcreteProductA1`和`ConcreteProductB1`组成,`ConcreteFactory2`创建的产品族由`ConcreteProductA2`和`ConcreteProductB2`组成。

客户端代码通过具体工厂来创建一组相关的具体产品对象,并调用其方法。使用抽象工厂模式,可以方便地替换具体工厂和具体产品,扩展新的产品族也更加容易。

四,建造者模式

1,介绍

建造者模式的基本思想是将一个复杂对象的构建过程分解成若干个简单的步骤,然后用一个统一的接口来表示这些步骤,从而使得同样的构建过程可以构建不同的表示。在建造者模式中,指挥者类负责协调各个构建者来完成对象的构建,客户端只需要与指挥者类进行交互即可。

建造者模式(Builder Pattern)是一种创建型设计模式,它允许将复杂对象的构建过程与其表示相分离。通过使用相同的构建过程可以创建不同的表示。

2.代码示例

建造者模式中包含以下角色:

- 产品(Product):具有多个部件的复杂对象。

- 抽象建造者(Builder):定义了创建一个产品所需要的所有方法,并且返回一个完整的产品。

- 具体建造者(Concrete Builder):实现了抽象建造者接口,负责创建一个具体产品。

- 指挥者(Director):调用具体建造者来创建产品对象的类。

下面是一个简单的示例,演示了建造者模式在Java中的实现:

// 产品类
class Product {
    private String partA;
    private String partB;
    private String partC;
    public String getPartA() {
        return partA;
    }
    public void setPartA(String partA) {
        this.partA = partA;
    }
    public String getPartB() {
        return partB;
    }
    public void setPartB(String partB) {
        this.partB = partB;
    }
    public String getPartC() {
        return partC;
    }
    public void setPartC(String partC) {
        this.partC = partC;
    }
}
// 抽象建造者
interface Builder {
    void buildPartA();
    void buildPartB();
    void buildPartC();
    Product getResult();
}
// 具体建造者
class ConcreteBuilder implements Builder {
    private Product product = new Product();
    @Override
    public void buildPartA() {
        product.setPartA("Part A");
    }
    @Override
    public void buildPartB() {
        product.setPartB("Part B");
    }
    @Override
    public void buildPartC() {
        product.setPartC("Part C");
    }
    @Override
    public Product getResult() {
        return product;
    }
}
// 指挥者
class Director {
    public void construct(Builder builder) {
        builder.buildPartA();
        builder.buildPartB();
        builder.buildPartC();
    }
}
// 客户端代码
public class Client {
    public static void main(String[] args) {
        Director director = new Director();
        Builder builder = new ConcreteBuilder();
        director.construct(builder);
        Product product = builder.getResult();
        System.out.println("Product parts: " + product.getPartA() + ", " + product.getPartB() + ", " + product.getPartC());
    }
}

image.gif

在上述示例中,产品类`Product`表示一个具有多个部件的复杂对象。抽象建造者接口`Builder`定义了一系列创建产品所需的方法,并且返回一个完整的产品。具体建造者类`ConcreteBuilder`实现了抽象建造者接口,在实现过程中保存一个产品实例,并负责构建该产品的各个部分。指挥者`Director`负责调用具体建造者来创建产品对象。

客户端代码首先创建一个指挥者实例和一个具体建造者实例,然后通过指挥者调用具体建造者中的方法来构建产品对象。最后,客户端代码通过具体建造者来获取构建完成的产品对象,并访问产品的各个部分。

使用建造者模式的好处是可以将一个复杂对象的构建过程独立出来,从而使其易于理解、维护和扩展。同时,相同的构建过程也可以用于创建不同的表示。

五.原型模式

1.介绍

原型模式是一种创建型设计模式,它允许创建复杂对象的副本,同时又能保持其结构不变。在原型模式中,通过拷贝来创建新的对象,而不是通过new来创建。这样可以避免在代码中显式调用构造函数,从而提高代码灵活性和可维护性。

2.代码示例

原型模式包含以下几个角色:

1. 抽象原型类(Prototype):声明了一个克隆自身的接口。

2. 具体原型类(ConcretePrototype):实现了克隆接口,返回一个自身的副本。

3. 客户端(Client):使用原型对象的客户端,向原型对象发出请求,以克隆自身来创建新的对象。

// 抽象原型类
interface Prototype {
    Prototype clone();
}
// 具体原型类
class ConcretePrototypeA implements Prototype {
    private String name;
    public ConcretePrototypeA(String name) {
        this.name = name;
    }
    @Override
    public Prototype clone() {
        return new ConcretePrototypeA(name);
    }
    public String getName() {
        return name;
    }
}
// 客户端
public class Client {
    public static void main(String[] args) {
        ConcretePrototypeA prototype = new ConcretePrototypeA("prototypeA");
        ConcretePrototypeA clone = (ConcretePrototypeA)prototype.clone();
        System.out.println(clone.getName());
    }
}

image.gif

在上述示例中,抽象原型类`Prototype`声明了一个克隆自身的接口。具体原型类`ConcretePrototypeA`实现了克隆接口`clone()`,并且在实现过程中返回一个自身的副本。客户端代码使用具体原型类来创建一个原型对象并调用其`clone()`方法来克隆一个新对象,最后输出克隆出来的对象的名称。

使用原型模式的好处是可以避免在代码中显式调用构造函数,从而提高代码灵活性和可维护性。同时,通过克隆来创建对象也可以避免一些不必要的资源消耗,从而提高程序的运行效率。

目录
相关文章
|
5天前
|
Java 索引
String字符串常用函数以及示例 JAVA基础
String字符串常用函数以及示例 JAVA基础
|
4天前
|
设计模式 算法 Java
Java一分钟之-设计模式:策略模式与模板方法
【5月更文挑战第17天】本文介绍了策略模式和模板方法模式,两种行为设计模式用于处理算法变化和代码复用。策略模式封装不同算法,允许客户独立于具体策略进行选择,但需注意选择复杂度和过度设计。模板方法模式定义算法骨架,延迟部分步骤给子类实现,但过度抽象或滥用继承可能导致问题。代码示例展示了两种模式的应用。根据场景选择合适模式,以保持代码清晰和可维护。
9 1
|
4天前
|
设计模式 Java
Java一分钟之-设计模式:装饰器模式与代理模式
【5月更文挑战第17天】本文探讨了装饰器模式和代理模式,两者都是在不改变原有对象基础上添加新功能。装饰器模式用于动态扩展对象功能,但过度使用可能导致类数量过多;代理模式用于控制对象访问,可能引入额外性能开销。文中通过 Java 代码示例展示了两种模式的实现。理解并恰当运用这些模式能提升代码的可扩展性和可维护性。
19 1
|
4天前
|
设计模式 Java
Java一分钟之-设计模式:工厂模式与抽象工厂模式
【5月更文挑战第17天】本文探讨了软件工程中的两种创建型设计模式——工厂模式和抽象工厂模式。工厂模式提供了一个创建对象的接口,延迟实例化到子类决定。过度使用或违反单一职责原则可能导致问题。代码示例展示了如何创建形状的工厂。抽象工厂模式则用于创建一系列相关对象,而不指定具体类,但添加新产品可能需修改现有工厂。代码示例展示了创建颜色和形状的工厂。根据需求选择模式,注意灵活性和耦合度。理解并恰当运用这些模式能提升代码质量。
16 2
|
5天前
|
设计模式 搜索推荐 数据库连接
第二篇 创建型设计模式 - 灵活、解耦的创建机制
第二篇 创建型设计模式 - 灵活、解耦的创建机制
|
2天前
|
Java 测试技术
如何提高Java代码的可读性
Java是一种常用的编程语言,但是写出易懂且可读性高的代码却是一项挑战。本文将分享一些技巧和建议,帮助您提高Java代码的可读性和可维护性。
|
4天前
|
设计模式 Java
Java一分钟之-设计模式:观察者模式与事件驱动
【5月更文挑战第17天】本文探讨了Java中实现组件间通信的观察者模式和事件驱动编程。观察者模式提供订阅机制,当对象状态改变时通知所有依赖对象。然而,它可能引发性能问题、循环依赖和内存泄漏。代码示例展示了如何实现和避免这些问题。事件驱动编程则响应用户输入和系统事件,但回调地狱和同步/异步混淆可能造成困扰。JavaFX事件驱动示例解释了如何处理事件。理解这两种模式有助于编写健壮的程序。
10 1
|
5天前
|
设计模式 SQL 安全
Java一分钟之-设计模式:单例模式的实现
【5月更文挑战第16天】本文介绍了单例模式的四种实现方式:饿汉式(静态初始化)、懒汉式(双检锁)、静态内部类和枚举单例,以及相关问题和解决方法。关注线程安全、反射攻击、序列化、生命周期和测试性,选择合适的实现方式以确保代码质量。了解单例模式的优缺点,谨慎使用,提升设计效率。
20 3
|
5天前
|
Java Kotlin
java调用kotlin代码编译报错“找不到符号”的问题
java调用kotlin代码编译报错“找不到符号”的问题
17 10
|
6天前
|
前端开发 Java Spring
Java Web ——MVC基础框架讲解及代码演示(下)
Java Web ——MVC基础框架讲解及代码演示
13 1