您现在的位置是:首页 >学无止境 >【设计模式二十三剑】✨编写更高质量代码的秘诀✨网站首页学无止境
【设计模式二十三剑】✨编写更高质量代码的秘诀✨
文章目录
- ✨✨简述
- ?【万能之门】简单工厂模式(Simple Factory)
- ?【制造之剑】工厂方法模式(Factory Method)
- ?【生产之剑】抽象工厂模式(Abstract Factory)
- ?【组装之剑】构造者模式(Builder)
- ?【复制之剑】原型模式(Prototype)
- ?【孤独之剑】单例模式(Singleton)
- ?【调和之剑】适配器模式(Adapter)
- ?【联通之剑】桥接模式(Bridge)
- ?【合力之剑】组合模式(Composite)
- ?【加持之剑】装饰器模式(Decorator)
- ?【掌控之剑】外观模式(Facade)
- ?【共享之剑】享元模式(Flyweight)
- ?【护卫之剑】代理模式(Proxy)
- ? 【承载之剑】责任链模式(Chain of Responsibility)
- ? 【掌舵之剑】命令模式(Command)
- ? 【解谜之剑】解释器模式(Interpreter)
- ? 【漫游之剑】迭代器模式(Iterator)
- ? 【调解之剑】中介者模式(Mediator)
- ? 【回溯之剑】备忘录模式(Memento)
- ? 【注视之剑】观察者模式(Observer)
- ? 【转换之剑】状态模式(State)
- ? 【取舍之剑】策略模式(Strategy)
- ? 【规范之剑】模板方法模式(Template Method)
- ? 【访问之剑】访问者模式(Visitor)
✨✨简述
?设计模式描述了一个在我们周围不断重复发生的问题,以及该问题的解决方案的核心。这样就能一次又一次地使用该方案而不必做重复劳动。核心在于提供了相关问题的解决方案,使得人们可以更加简单方便地复用成功的设计和体系结构
。
?设计模式是在软件工程中广泛使用的经过反复验证的解决方案,它们可以用来解决常见的设计问题。设计模式是对软件开发中经常出现的一些问题的一种通用解决方案,它们可以提高软件的可维护性、可重用性、灵活性和可扩展性
。设计模式提供了一种通用的词汇和标准术语,使软件开发人员可以更加清晰地交流和理解软件设计和实现。同时,设计模式还可以加快软件开发过程,提高开发效率。
?设计模式的四个基本要素:模式名称、问题、解决方案、效果
。
??按照目的可以分为三类:
创建型模式(Creational Patterns)
:主要关注对象的创建过程,包括如何实例化对象、如何组织对象的创建结构等。结构型模式(Structural Patterns)
:主要关注对象和类的组合方式,以及对象和类之间的组合方式。行为型模式(Behavioral Patterns)
:主要关注对象和类之间的通信方式,以及负责协调和控制类之间的交互。
==========================================================================================
?【万能之门】简单工厂模式(Simple Factory)
?简单工厂模式属于创建型模式,但不属于23种设计模式之一。
简单工厂模式可以通过一个工厂类创建不同的对象,就像开启了一个万能的
门,可以制造出不同的产品。定义一个工厂类,它可以根据参数的不同返回不同类的实例,被创建的实例通常都具有共同的父类 。因为在简单工厂模式中用于创建实例的方法是静态(static)方法,因此简单工厂模式又被称为静态工厂方法(Static Factory Method) 模式,它属于类创建型模式
。
结构图如下:
??有三类角色
- Factory(工厂角色):简单工厂模式的核心,负责实现创建所有产品的内部逻辑,工厂类可以被外界直接调用,创建所需对象。
- Product(抽象产品角色):工厂类所创建的所有对象的父类,封装了产品对象的公共方法,所有的具体产品为其子类对象。
- ConcreteProduct(具体产品角色):简单工厂模式的创建目标,所有被创建的对象都是某个具体类的实力,它要实现抽象产品中声明的抽象方法。
代码实现:
public class SimpleFactory {
public static void main(String[] args) {
Product productA = Factory.createProduct("A");
productA.info();
Product productB = Factory.createProduct("B");
}
}
// 抽象产品角色
abstract class Product {
public abstract void info();
}
// 工厂角色
class Factory {
public static Product createProduct(String type) {
Product product = null;
switch (type) {
case "A":
product = new ProductA();
break;
case "B":
product = new ProductB();
break;
default:
System.out.println("没有 " + type + " 类型的产品!");
break;
}
return product;
}
}
// 产品A
class ProductA extends Product {
@Override
public void info() {
System.out.println("产品的信息:A");
}
}
// 产品B
class ProductB extends Product {
@Override
public void info() {
System.out.println("产品的信息:B");
}
}
?优缺点:
【优点】
? 1、简单工厂模式将对象的创建过程集中在一个工厂类中,客户端无需知道具体的创建过程,只需要传递对应的参数即可创建对象,降低了客户端的复杂度和耦合度。
? 2、简单工厂模式可以根据不同的参数创建不同的对象,提高了代码的可扩展性和灵活性。
【缺点】
? 1、简单工厂模式的工厂类通常包含了所有的对象创建逻辑,如果需要增加新的产品,则需要修改工厂类的代码,违反了开闭原则。
? 2、工厂类负责创建所有的对象,当创建的对象过多时,工厂类会变得十分臃肿,难以维护。
? 3、简单工厂模式的扩展性有限,无法应对复杂的业务需求。
==========================================================================================
?【制造之剑】工厂方法模式(Factory Method)
【刀光剑影,转瞬即逝,千变万化,百般精通。】
? 工厂方法模式是一种创建型设计模式,是简单工厂模式的延伸,它提供了一种将对象的实例化过程封装在子类中进行的方法
。在工厂方法模式中,抽象工厂定义了一个创建对象的接口,由其具体子类来决定要实例化的类,而具体实例化的过程则延迟到具体子类中进行
。
工厂方法模式将对象的创建过程分离出来
,使得客户端不需要知道具体的实现细节,只需要知道一个工厂接口即可,从而使系统更加灵活可扩展。
在工厂方法模式中,通常会定义一个抽象工厂接口和若干个具体的工厂类,每个工厂类负责创建一种具体的产品对象
。同时,定义一个抽象产品接口和若干个具体的产品类,每个产品类负责实现具体的产品功能
。客户端通过工厂接口来创建产品对象,不同的工厂实现类对应不同的产品对象。
结构图如下:
? 工厂方法模式适用于:
- 当一个类不知道它所必须创建的对象的类的时候。
- 当一个类希望由它的子类来指定它所创建的对象的时候。
- 当类将创建对象的职责委托给多个帮助子类中的某一个,并且你希望将哪一个帮助子类是代理者这一信息局部化的时候。
代码实现:
public class FactoryMethod {
public static void main(String[] args) {
Factory factoryA = new FactoryA();
// 父类 对象名 = new 子类();
Product productA = factoryA.createProduct();
// Product productA = new ProductA();
productA.info();
Factory factoryB = new FactoryB();
Product productB = factoryB.createProduct();
productB.info();
}
}
// class Factory
interface Factory {
public Product createProduct();
}
class FactoryA implements Factory {
@Override
public Product createProduct() {
return new ProductA();
}
}
class FactoryB implements Factory {
@Override
public Product createProduct() {
return new ProductB();
}
}
// abstract class Product
interface Product {
// public abstract void info();
public void info();
}
// class ProductA extends Product
class ProductA implements Product {
@Override
public void info() {
System.out.println("产品的信息:A");
}
}
// class ProductB extends Product
class ProductB implements Product {
@Override
public void info() {
System.out.println("产品的信息:B");
}
}
?优缺点:
【优点】
? 1、可以使系统更加灵活可扩展,可以动态地增加或修改产品类而不会影响到客户端代码。
? 2、符合“开闭原则”,即对扩展开放、对修改关闭,增加新的产品类只需要增加对应的工厂类即可,不需要修改原有代码。
? 3、降低了客户端和产品对象之间的耦合度,客户端只需要知道抽象工厂和抽象产品接口即可,具体的产品对象由具体的工厂类来创建。
? 4、工厂方法模式可以使用多态性,即客户端可以针对抽象工厂和抽象产品接口编程,而在运行时可以动态地替换具体的工厂类和产品类。
【缺点】
? 1、需要定义大量的类,增加了系统的复杂度。
? 2、工厂方法模式中的抽象产品类只能定义一些抽象的方法,而不能实现具体的功能,这限制了产品的功能扩展性。
? 3、客户端需要知道具体工厂类的存在,这增加了客户端的使用难度。
==========================================================================================
?【生产之剑】抽象工厂模式(Abstract Factory)
【刀刃之上,锋芒毕露,不止于形,更注重意。】
? 抽象工厂模式是一种创建型设计模式,它提供了一种接口,可以创建一系列相关或相互依赖的对象,而无需指定它们的具体类
。它是工厂方法模式的一种升级版,工厂方法模式只能创建一种类型的对象,而抽象工厂模式可以创建多个不同类型的对象。它可以帮助客户端隔离具体类的创建,同时提供了一种将系统的各个部分组合起来的方法。
抽象工厂模式通常包含一个抽象工厂类和多个具体工厂类
,每个具体工厂类负责创建一组相关的产品对象
。抽象工厂类定义了用于创建这些产品对象的接口,而具体工厂类则实现了这些接口。
抽象工厂模式的核心是抽象工厂类,该类定义了一系列用于创建产品的方法,这些方法通常被设计为抽象的,这样具体的工厂类就必须实现这些方法来创建具体的产品对象。另外,抽象工厂类也可以定义一些公共的方法和属性,用于描述所创建的产品对象的特性
结构图如下:
?抽象工厂模式适用于:
- 一个系统要独立于它的产品创建、组合和表示时。
- 一个系统要由多个产品系列中的一个来配置时。
- 当要强调一系列相关的产品对象的设计以便进行联合使用时。
- 当提供一个产品类库,只想显示它们的接口而不是实现时。
代码实现:
public class AbstractFactory {
public static void main(String[] args) {
Factory factory1 = new Factory1();
ProductA productA = factory1.createProductA();
productA.info();
Factory factory2 = new Factory2();
ProductB productB = factory2.createProductB();
productB.info();
}
}
interface Factory {
public ProductA createProductA();
public ProductB createProductB();
}
class Factory1 implements Factory {
@Override
public ProductA createProductA() {
return new ProductA1();
}
@Override
public ProductB createProductB() {
return new ProductB1();
}
}
class Factory2 implements Factory {
@Override
public ProductA createProductA() {
return new ProductA2();
}
@Override
public ProductB createProductB() {
return new ProductB2();
}
}
interface ProductA {
public void info();
}
class ProductA1 implements ProductA {
@Override
public void info() {
System.out.println("产品的信息:A1");
}
}
class ProductA2 implements ProductA {
@Override
public void info() {
System.out.println("产品的信息:A2");
}
}
interface ProductB {
public void info();
}
class ProductB1 implements ProductB {
@Override
public void info() {
System.out.println("产品的信息:B1");
}
}
class ProductB2 implements ProductB {
@Override
public void info() {
System.out.println("产品的信息:B2");
}
}
?优缺点:
【优点】
? 1、可以保证同一工厂生产出的产品系列是相互关联或相互依赖的。
? 2、抽象工厂模式使得产品的切换变得容易,只需要更改具体工厂即可。
? 3、可以使客户端代码与具体产品的实现分离,客户端代码只需要关心抽象产品的接口,而不需要关心具体产品的实现。
【缺点】
? 1、抽象工厂模式的扩展性比较困难,因为抽象工厂接口中已经确定了可以创建的产品族,如果需要增加新的产品族,则需要修改抽象工厂接口,这样会影响到所有的具体工厂类。
? 2、增加新的产品等级结构(即增加新的抽象产品和相应的具体产品)比较困难,因为需要修改所有的具体工厂类。
==========================================================================================
?【组装之剑】构造者模式(Builder)
【慧眼识珠,从零开始,耐心细致,打造完美。】
? 构造者模式是一种创建型设计模式,用于创建复杂对象。它提供一种分步骤创建对象的方法,使得同样的构建过程可以创建不同的表示
。
构造者模式的核心概念是将一个复杂对象的构建过程与其表示分离,使得同样的构建过程可以创建不同的表示形式
。它通过一个构造者类(Builder)来封装对象的构建过程,并提供一系列的方法来设置对象的属性或组件。然后,通过调用构造者类的方法,逐步构建对象,最终返回构建好的对象。
结构图如下:
? 构造者模式适用于:
- 当构造过程必须允许被构造的对象有不同表示时。
- 当创建复杂对象的算法,应独立于该对象的组成部分、以及组装方式时。
代码实现:
import java.util.*;
public class Main {
public static void main(String[] args) {
Director director = new Director();
Builder builder1 = new Builder1();
director.Construct(builder1);
Product product1 = builder1.getResult();
product1.show();
Builder builder2 = new Builder2();
director.Construct(builder2);
Product product2 = builder2.getResult();
product2.show();
}
}
class Director {
public void Construct(Builder builder) {
builder.BuildPart();
}
}
abstract class Builder {
public abstract void BuildPart();
public abstract Product getResult();
}
class Builder1 extends Builder {
Product product = new Product();
@Override
public void BuildPart() {
product.Add("A");
product.Add("B");
product.Add("C");
product.Add("D");
product.Add("E");
product.Add("F");
}
@Override
public Product getResult() {
return product;
}
}
class Builder2 extends Builder {
Product product = new Product();
@Override
public void BuildPart() {
product.Add("A");
product.Add("B");
product.Add("C");
}
@Override
public Product getResult() {
return product;
}
}
class Product {
List<String> parts = new ArrayList<String>();
public void Add(String part) {
parts.add(part);
}
public void show() {
System.out.print("产品的组成:");
for (String s : parts)
System.out.print(s + " ");
System.out.print("
");
}
}
?优缺点:
【优点】
? 1、封装复杂对象的构建过程:构造者模式将复杂对象的构建过程封装在一个独立的构造者类中,使得使用者无需关注对象的创建细节,只需通过简单的调用构造者的方法来构建对象。
? 2、可以创建不同表示的对象:通过调整构造者的步骤和顺序,可以创建具有不同属性配置的对象,满足不同的需求。这种灵活性使得构造者模式在创建复杂对象时非常有用。
? 3、提高代码的可读性和可维护性:由于构造者模式将对象的构建过程拆分为多个步骤,并通过方法链式调用的方式进行配置,使得代码更加清晰、易读,也更易于维护和扩展。
? 4、逐步构建对象:构造者模式支持逐步构建对象,每一步都可以设置对象的属性或组件。这种逐步构建的方式使得构建过程更加灵活,可以根据需要动态调整对象的属性。
【缺点】
? 1、增加了代码量:构造者模式引入了额外的构造者类,增加了代码量和类的数量。对于简单的对象创建,使用构造者模式可能会显得过于繁琐。
? 2、增加了系统的开销:由于构造者模式要求逐步构建对象,可能会增加系统的开销。如果对象的创建过程简单且固定,使用构造者模式可能会显得冗余。
? 3、不适用于创建不可变对象:构造者模式通常用于创建可变对象,如果需要创建不可变对象,可能需要额外的处理来保证对象的不可变性。
==========================================================================================
?【复制之剑】原型模式(Prototype)
? 原型模式是一种创建型设计模式,它允许通过复制(克隆)现有对象来创建新对象,而无需显式地使用构造函数。该模式基于一个原型对象,通过复制该原型对象的属性和状态来创建新的对象实例,从而实现对象的复制和创建。
原型模式的核心思想是将对象的创建委托给原型对象,原型对象作为一个可复制的模板,定义了对象的结构和初始状态
。通过克隆原型对象,可以创建出与原型相同的新对象,而且新对象的创建过程可以根据需要进行定制和扩展。
结构图如下:
? 原型模式适用于:
- 一个系统要独立于它的产品的创建、构成和表示时。
- 当要实例化的类是在运行时刻指定时,例如,通过动态装载。
- 为了避免创建一个与产品类层次平行的工厂类层次时。
- 当一个类的实例只能有几个不同状态组合中的一种时。建立相应数目的原型并克隆它们,可能比每次用合适的状态手工实例化该类更方便一些。
代码实现:
public class Main {
public static void main(String[] args) {
Product product1 = new Product(2022, 5.28);
System.out.println(product1.getId() + " " + product1.getPrice());
// Product product2 = new Product(2022, 5.28);
Product product2 = (Product) product1.Clone();
System.out.println(product2.getId() + " " + product2.getPrice());
Product product3 = (Product) product1.Clone();
System.out.println(product3.getId() + " " + product3.getPrice());
}
}
interface Prototype {
public Object Clone();
}
class Product implements Prototype {
private int id;
private double price;
public Product() {}
public Product(int id, double price) {
this.id = id;
this.price = price;
}
public int getId() {
return id;
}
public double getPrice() {
return price;
}
@Override
public Object Clone() {
Product object = new Product();
object.id = this.id;
object.price = this.price;
return object;
}
}
?优缺点:
【优点】
? 1、简化对象创建:原型模式通过克隆原型对象来创建新对象,避免了使用复杂的构造函数进行对象初始化的过程,使对象创建变得简单和直观。
? 2、提高性能:与直接创建对象相比,克隆原型对象可以提高对象创建的速度,避免了重复的初始化过程,特别是对于创建开销较大的对象而言,性能的提升更为显著。
? 3、实现对象定制化:原型模式允许动态地添加或修改原型对象的属性和行为,通过修改原型对象的克隆结果,可以实现对象的个性化定制。
【缺点】
? 1、克隆对象的复杂性:某些对象的克隆可能涉及到引用类型属性的处理,需要特别注意对象的引用关系和克隆的深浅复制问题。复杂对象的克隆可能会增加代码的复杂性。
? 2、内存消耗:原型模式需要在内存中保存原型对象,当需要大量创建对象时,会增加内存消耗。特别是深克隆的情况下,可能会占用更多的内存空间。
? 3、克隆与继承的冲突:在某些语言中,原型模式与继承机制存在冲突,因为克隆对象是通过复制已有对象来创建的,而不是通过继承父类来创建。
==========================================================================================
?【孤独之剑】单例模式(Singleton)
? 单例模式是一种创建型设计模式,它确保一个类只有一个实例对象
,并提供全局访问点。
在单例模式中,类的构造函数被私有化,防止外部代码直接实例化对象。而通过定义一个静态方法或静态变量,让类自身负责创建并管理唯一的实例对象。每次调用该静态方法时,都返回同一个实例对象。
结构图如下:
?单例模式适用于:
- 当类只能有一个实例而且客户可以从一个 从所周知的访问点访问它时。
- 当这个唯一实例应该是通过子类化可扩展的,并且客户无须更改代码就能使用一个扩展的实例时。
代码实现:
public class SingletonPattern {
public static void main(String[] args) {
// Singleton singleton1 = new Singleton();
Singleton singleton1 = Singleton.getInstance();
Singleton singleton2 = Singleton.getInstance();
Singleton singleton3 = Singleton.getInstance();
System.out.println(singleton1.getNumber() + " " + singleton2.getNumber() + " " + singleton3.getNumber());
singleton1.setNumber(528);
System.out.println(singleton1.getNumber() + " " + singleton2.getNumber() + " " + singleton3.getNumber());
}
}
class Singleton {
private int number = 2022;
public void setNumber(int number) {
this.number = number;
}
public int getNumber() {
return number;
}
private static Singleton instance = new Singleton();
private Singleton() {}
public static Singleton getInstance() {
return instance;
}
}
?优缺点:
【优点】
? 1、确保只有一个实例:单例模式保证类只有一个实例对象,避免了多次实例化的开销和资源浪费。
? 2、全局访问点:通过单例模式,可以在程序的任何位置访问该实例对象,方便地共享和调用。
? 3、避免竞态条件:在多线程环境下,单例模式可以防止多个线程同时创建实例对象,避免了竞态条件和数据不一致的问题。
【缺点】
? 1、难以扩展和测试:因为单例模式将实例对象的创建和管理集中在类内部,对于扩展和测试来说可能会变得更加困难。
? 2、违反单一职责原则:单例模式负责创建和管理实例对象,可能导致类的职责不够清晰,违反了单一职责原则。
==========================================================================================
?【调和之剑】适配器模式(Adapter)
? 适配器模式是一种结构型设计模式,用于将一个类的接口转换成另一个接口,使得不兼容的类能够一起工作
。
适配器模式的核心概念是适配器(Adapter),它充当两个不兼容类之间的桥梁。适配器接受一个类的请求,并将其转换为另一个类可以理解的格式。
结构图如下:
?适配器模式适用于:
- 想使用一个已经存在的类,而它的接口不符合要求。
将Type-C接口通过适配器插入到USB接口
代码实现:
public class AdapterPattern {
public static void main(String[] args) {
USB usb = new Adapter();
usb.Request();
}
}
class USB {
public void Request() {
System.out.println("USB数据线");
}
}
class Adapter extends USB {
private TypeC typeC = new TypeC();
@Override
public void Request() {
typeC.SpecificRequest();
}
}
class TypeC {
public void SpecificRequest() {
System.out.println("Type-C数据线");
}
}