设计模式三大类详解:创建型、结构型、行为型模式及其应用原则

行为型模式主要关注对象之间的交互和职责分配。

设计模式三大类详解:创建型、结构型、行为型模式及其应用原则

创建型模式、结构型模式、行为型模式是常见的面向对象设计原则。其中有 1、迪米特法则,它又称最少知道原则(Demeter Principle)。

最少知道原则的含义是:一个实体应尽量减少与其他实体的相互作用,以让系统的功能模块保持相对独立。

从依赖者的角度来说,只依赖应该依赖的对象。

从被依赖者的角度说,只暴露应该暴露的方法。降低耦合

2、里氏代换原则

基类与子类之间存在着一定的关系。子类具备扩展父类功能的能力,然而却不能对父类原有的功能进行改变。具体而言:当子类继承父类时,除了添加新的方法来实现新增功能之外,应尽量避免对父类的方法进行重写。

依赖倒置原则指的是一种原则,它强调在设计和编程中,应该依赖于抽象而不是具体的实现。具体来说,就是高层模块不应该依赖于低层模块,两者都应该依赖于抽象;抽象不应该依赖于具体细节,具体细节应该依赖于抽象。这样可以提高代码的可维护性、可扩展性和可测试性。

它降低了客户与实现模块之间的耦合。

在软件设计中,细节具有多变的特点,抽象层相对稳定。所以,以抽象为基础搭建的架构比以细节为基础搭建的架构更稳定。这里的抽象指的是接口或者抽象类,细节指的是具体的实现类。

使用接口或抽象类的目的在于制定规范和契约,不涉及具体操作,将展现细节的任务交给它们的实现类去完成。

接口隔离原则,即 Interface Segregation Principle 。它强调将臃肿庞大的接口拆分成多个专门的小接口,每个接口只负责处理特定的行为或职责,而不是将所有的行为都放在一个大接口中。这样可以降低接口的复杂性,提高系统的可维护性和可扩展性。同时,也能更好地满足不同客户类的需求,避免客户端依赖于它不需要的方法。

这个原则意味着:相比使用单个接口,使用多个隔离的接口是更好的。它还意味着:能够降低类之间的耦合度。

5、开闭原则(Open Close Principle)

开闭原则的意思是:对扩展开放,对修改关闭。

当程序需要拓展时,不能对原有代码进行修改,以实现热插拔的效果。也就是说,这样做是为了让程序具有良好的扩展性,便于维护和升级。要达到这样的效果,我们就得使用接口和抽象类。

单一原则就是复合复用原则。

一个类单一职责,防止耦合

设计模式分类:

创建型模式包含工厂方法模式、抽象工厂模式、单例模式、建造者模式、原型模式,其中还有简单工厂模式。

结构型模式包含代理模式、装饰器模式、适配器模式、外观模式、组合模式、享元模式、桥接模式。

行为型模式包含观察者模式、责任链模式、模板方法模式、策略模式、迭代子模式、命令模式、状态模式、备忘录模式、访问者模式、中介者模式、解释器模式。

创建型模式工厂模式

工厂模式是一种创建对象的设计模式。它可以通过一个工厂类来创建对象,而不是直接使用 new 关键字。

// 产品接口
interface Product {
    String sale();
}
// 具体产品A
产品 A 这个类实现了 Product 接口。
    @Override
    public String sale() {
        return "Sale ProductA";
    }
}
// 具体产品B
产品 B 类实现了产品接口。
    @Override
    public String sale() {
        return "Sale ProductB";
    }
}
// 工厂类
class ProductFactory {
创建一个产品的静态方法,该方法接收一个字符串类型的产品类型作为参数,用于创建产品。
如果产品类型等于“A”(不区分大小写),那么……
            return new ProductA();
如果 productType 等于 "B"(不区分大小写),那么就执行以下操作。
            return new ProductB();
        }
    }
}
// 客户端代码
public class Client {
公共静态的 void 主方法(String 数组 args)。
Product productA 是由 ProductFactory 创建的产品,其类型为 "A"。
输出 productA 的销售结果。
Product productB 是由 ProductFactory 创建的产品,其类型为 "B"。
System 显示 productB 的销售信息。
    }
}

抽象工厂模式:

// 抽象产品:饮料
interface Beverage {
    String serve();
}
// 抽象产品:小吃
interface Snack {
    String serve();
}
// 具体产品:咖啡
咖啡类实现了饮料类。
    public String serve() {
        return "Serving Coffee";
    }
}
// 具体产品:茶
Tea 是一种饮料,它实现了 Beverage 接口。
    public String serve() {
        return "Serving Tea";
    }
}
// 具体产品:薯片
Chips 属于 Snack 这一类别。Chips 具备 Snack 的相关特性。Chips 被归类为 Snack 。
    public String serve() {
        return "Serving Chips";
    }
}
// 具体产品:饼干
Cookies 是 Snack 中的一种。
    public String serve() {
        return "Serving Cookies";
    }
}
// 抽象工厂
- 具备饮料相关的功能和操作。
    Beverage createBeverage();
    Snack createSnack();
}
// 具体工厂:咖啡和薯片工厂
咖啡和薯片工厂属于食品和饮料工厂的范畴。
创建一个饮料的方法是 public Beverage createBeverage()。 这个方法用于创建一个饮料对象。 它会执行一些特定的操作来初始化饮料的属性或状态。 最终返回创建好的饮料对象。
        return new Coffee();
    }
    public Snack createSnack() {
        return new Chips();
    }
}
// 具体工厂:茶和饼干工厂
TeaAndCookiesFactory 这个类实现了 FoodAndBeverageFactory 接口。
    public Beverage createBeverage() {
        return new Tea();
    }
    public Snack createSnack() {
        return new Cookies();
    }
}
// 客户端代码
public class Client {
    public static void main(String[] args) {
FoodAndBeverageFactory 这个对象被初始化为一个 CoffeeAndChipsFactory;
System.out.println(coffeeAndChipsFactory.createBeverage().serve());  // 输出: Serving Coffee
System.out.println("Serving Chips");  // 输出: Serving Chips
FoodAndBeverageFactory 拥有一个名为 teaAndCookiesFactory 的对象,这个对象是通过 new TeaAndCookiesFactory() 创建的。
// 输出: 提供茶
// 输出: Serving Cookies
    }
}

工厂模式和抽象工厂模式均为常用的设计模式,主要是用于对象的创建。它们存在一些相似的地方,然而也有着显著的差别。

共同点在于封装对象的创建:它们都通过这种方式,把客户端代码和具体的实现类分隔开来。

使用工厂方法来创建对象,而非直接使用 new 关键字。

遵循开闭原则:当需要增加新的产品时,能够做到在不改动客户端代码的前提下,借助增加新的产品类去对系统进行扩展。

工厂类承担对象创建的职责,客户端则负责对象的使用。 工厂类的职责是负责对象的创建,而客户端的职责是负责对象的使用。 工厂类专注于对象的创建,客户端专注于对象的使用。 工厂类的工作是负责对象的创建,客户端的工作是负责对象的使用。 工厂类主要负责对象的创建,客户端主要负责对象的使用。

不同点产品类型:接口设计:建造者模式(Builder)

在 Java 里,建造者模式属于一种创建对象的设计模式。这种模式能够允许通过多个步骤去构建一个较为复杂的对象。

传统的 set 和 get 方法用于对象装配,与之相比,引入静态内部类的构建者模式具有几个显著优点:

可读性和可维护性:

构建者模式能让对象的创建过程更为清晰,特别是在需要设置多个属性的情况下。通过链式调用能够提升代码的可读性。

不可变性:

构建者模式通常会返回一个对象,这个对象是不可变的。通过返回不可变对象,能够避免在对象创建之后被意外地修改,从而增强了对象的安全性。

简化复杂对象的创建:

对于有多个参数的对象,构建者模式能够给出默认值,这样就避免了构造函数参数数量过多的情况。

灵活性:

构建者模式能在创建对象时运用不同的参数组合,并且无需创建多个构造函数。

分离构建和表示:

构建者模式能把对象的构建过程和其表示分离开来,这样一来,相同的构建过程就能够创建出不同的表示。

支持可选参数:

在构建者模式里,能够很轻松地去处理那些可选参数,并且不需要通过在构造函数中使用重载的方式来处理。

public class Person {
    private final String name;
    private final int age;
    private final String address;
一个私有的 Person 类的构造函数接收一个 Builder 对象作为参数。这个构造函数用于创建 Person 对象。在构造函数内部,通过 Builder 对象的属性来初始化 Person 对象的相应属性。
        this.name = builder.name;
        this.age = builder.age;
this 的地址等于 builder 的地址。
    }
    public static class Builder {
        private String name;
        private int age;
        private String address;
公共的构建器,其作用是为名称进行设置。通过这个构建器,可以传入一个名为 name 的字符串参数,从而对名称进行相关的操作和设置。
            this.name = name;
            return this;
        }
        public Builder age(int age) {
            this.age = age;
            return this;
        }
公共的构建器(Builder)用于设置地址(address)。它接收一个字符串类型的地址参数。通过这个方法,可以对构建器的地址属性进行设置。
            this.address = address;
            return this;
        }
        public Person build() {
            return new Person(this);
        }
    }
    @Override
    public String toString() {
使用 String.format 方法,将 name、age 和 address 等信息按照特定格式进行拼接,最终返回一个字符串,该字符串的格式为"Person{name='具体的 name 值', age=具体的 age 值, address='具体的 address 值'}"
    }
}
public class Main {
    public static void main(String[] args) {
创建一个 Person 的实例,通过 Person.Builder()来进行构建操作。
                .name("John Doe")
                .age(30)
                .address("123 Main St")
                .build();
        System.out.println(person);
    }
}

当面对创建过于复杂的对象时,如果不想对外暴露所有的创建方式,那么可以为构造者提供默认参数,只将必要参数接口对外暴露,以此来简化对象的创建。

原型模式

原型模式属于创建型设计模式。它主要的用途是通过对已有的对象进行克隆来创建新的对象。这样做能够提高性能,同时还可以避免构造函数所带来的约束。以下是关于原型模式的一些关键要点:

意图:通过复制一个已经存在的对象(原型)来创建新对象。

主要要解决的问题是,规避使用构造函数来创建对象所带来的复杂性,特别是当对象的创建成本比较高的时候。

关键代码:通常涉及到实现一个克隆方法,允许对象复制自身。

使用场景:

当一个类的实例化成本较高时。

当需要创建多个相似对象时。

浅拷贝与深拷贝:

浅拷贝:只复制对象的基本数据类型和引用类型的引用。

深拷贝的操作是复制对象以及它所引用的所有对象,这样能确保它们是完全独立的。需要继承 Cloneable 接口,然后重写 clone 方法,并且为复制的对象创建新的属性。同时还可以通过序列化来实现深拷贝。

你可能想看:
« 上一篇
下一篇 »

相关推荐

java中什么是冒泡,冒泡算法

2026年09月06日

27阅读

java中冒号,java双冒号

2026年09月06日

26阅读

java中的->,java中的是什么意思

2026年09月06日

24阅读

java中的super用法,Java中super的说明

2026年09月06日

28阅读

java中反射的应用,java中反射的应用场景

2026年09月06日

25阅读

java中开关的定义,Java关键字有哪些

2026年09月06日

25阅读