设计模式
一,介绍
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; // 提供全局访问点 } }
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; // 提供全局访问点 } }
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; // 提供全局访问点 } }
4. 枚举方式(Enum):
public enum Singleton { INSTANCE; // 利用枚举类型的特性,保证实例的唯一性和线程安全 // 可以添加其他方法和属性 public void doSomething() {} }
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; // 提供全局访问点 } }
双重检查锁模式中,使用两次判断实例是否为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(); } }
在上述示例中,抽象产品接口`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(); } }
在上述示例中,抽象工厂接口`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()); } }
在上述示例中,产品类`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()); } }
在上述示例中,抽象原型类`Prototype`声明了一个克隆自身的接口。具体原型类`ConcretePrototypeA`实现了克隆接口`clone()`,并且在实现过程中返回一个自身的副本。客户端代码使用具体原型类来创建一个原型对象并调用其`clone()`方法来克隆一个新对象,最后输出克隆出来的对象的名称。
使用原型模式的好处是可以避免在代码中显式调用构造函数,从而提高代码灵活性和可维护性。同时,通过克隆来创建对象也可以避免一些不必要的资源消耗,从而提高程序的运行效率。