创建型抽象了实例化过程
1 AbstractFactory抽象工厂
1.1 概念
抽象工厂可以理解为一个工厂的工厂,它提供了一种创建相关或者互相依赖对象家族的方式,而无需指定具体的类。这个“家族”可以由不同的工厂生产,但是它们所生产的对象必须是互相关联的。抽象工厂可以把这些关联对象的生产过程集中到一起,方便创建这个家族的各个成员对象。
当我们需要一个产品对象时,只需要找到对应的工厂就可以获取相应的产品.
以生产家具为例子,抽象工厂模式可以被理解为一家家具工厂的工厂,每个具体的工厂(如布艺工厂、皮制工厂),每个工厂会生产与自己相关的一组家具(沙发,茶几、电视柜等)但这些家具必须互相关联,以达到一个完整的家具家族
在这个例子中,抽象工厂模式将每个具体工厂)作为一个抽象工厂。每个家具(如沙发、茶几、电视柜)作为一个抽象产品。具体工厂实现了抽象工厂的接口,生产一组相互关联的抽象产品。
1.2代码示例
package com.cxq.creational;
public class AbstractFactory {
public static void main(String[] args) {
//布艺工厂
Factory factory1 = new FabricFactory();
System.out.println(factory1.createBed().getSize());
System.out.println(factory1.createSofa().getType());
// 皮具工厂
Factory factory2 = new LeatherFactory();
System.out.println(factory2.createSofa().getType());
System.out.println(factory2.createBed().getSize());
}
}
// 沙发接口
interface Sofa{
String getType();
}
//床接口
interface Bed{
String getSize();
}
class FabircSofa implements Sofa{
@Override
public String getType() {
return "布艺沙发";
}
}
class LeatherSofa implements Sofa{
@Override
public String getType() {
return "皮具沙发";
}
}
class SingleBed implements Bed{
@Override
public String getSize() {
return "单人床";
}
}
class DoubleBed implements Bed{
@Override
public String getSize() {
return "双人床";
}
}
// 定义抽象工厂
interface Factory{
Sofa createSofa();
Bed createBed();
}
//布艺工厂
class FabricFactory implements Factory{
@Override
public Sofa createSofa() {
return new FabircSofa();
}
@Override
public Bed createBed() {
return new SingleBed();
}
}
//皮具工厂
class LeatherFactory implements Factory {
@Override
public Sofa createSofa() {
return new LeatherSofa();
}
@Override
public Bed createBed() {
return new DoubleBed();
}
}
1.3 应用
2 Builder生成器
2.1 概念
生成器是为了创建复杂对象,它将对象的构造过程分解成多个简单的部分,并使用一个独立的构建器类来控制整个过程。这使得创建复杂对象的过程更加灵活,可维护性更高。 Builder设计模式通常由四个部分组成:产品、抽象构建器、具体构建器和指导者。
- 产品:需要被构建的对象,它由多个部分组成,每个部分可以是简单的数据类型或复杂的对象。
- 抽象构建器:定义了构建产品的接口和方法,具体构建器将实现这些方法。
- 具体构建器:实现了抽象构建器中定义的方法,并负责构建产品的不同部分。
- 指导者:负责指导具体构建器如何构建产品。
使用Builder设计模式,可以使得创建对象的过程更加灵活,可以按需添加或删除部分,而不需要改变整个构建过程。此外,
2.2 示例代码
比如构建一个用户对象,这里构建的较为简单。
public class Builder {
User user = new User.UserBuilder()
.withAge(12)
.withEmail("XXX@qq.com")
.withName("李华").build();
}
class User {
private String name;
private int age;
private String email;
private User(UserBuilder builder) {
this.name = builder.name;
this.age = builder.age;
this.email = builder.email;
}
public String getName() {
return name;
}
public int getAge() {
return age;
}
public String getEmail() {
return email;
}
public static class UserBuilder {
private String name;
private int age;
private String email;
public UserBuilder withName(String name) {
this.name = name;
return this;
}
public UserBuilder withAge(int age) {
this.age = age;
return this;
}
public UserBuilder withEmail(String email) {
this.email = email;
return this;
}
public User build() {
return new User(this);
}
}
}
使用Builder设计模式构建对象相比直接使用对象的set方法构建具有以下区别:
- 链式调用:Builder模式可以使用链式调用,可以通过一行代码构建出一个复杂对象,而使用set方法则需要一步步设置每一个属性值。
- 不可变性:Builder模式可以通过将类的属性设置为final来确保对象在构建完成后不可变,避免了对象被篡改的风险。
- 可读性:Builder模式可以使用具有描述性的方法名来设置属性值,使得代码更具有可读性和可维护性。
- 安全性:Builder模式可以通过将构建过程封装起来,确保对象的构建过程是线程安全的,避免了多线程同时对同一对象进行修改导致的数据不一致问题。
在标准的Builder设计模式中,一旦通过Builder构建出对象,对象的状态就被固定下来,无法再进行修改。这是因为Builder在构建对象时,将对象的各个属性都赋值给了对象本身,而不是通过setter方法一个个地设置属性值,这种方式避免了对象状态的后续修改。如果需要修改对象状态,需要重新使用Builder构建一个新的对象。
当然,这并不是说Builder模式的实现都必须这样,开发人员可以根据实际需求来进行设计和实现。有些Builder模式实现可能允许在构建对象之后对对象的某些属性进行修改,这样做可能会牺牲一定的安全性,但是可以提高灵活性。
3 FactoryMethod工厂方法
概念
它定义了一个用于创建对象的接口,但让子类决定实例化哪个类。工厂方法模式让类把实例化推迟到子类。
该模式的主要思想是创建一个用于创建对象的工厂接口,该接口包含一个用于创建对象的方法。子类可以实现此方法以创建对象的不同实例。这种方法的好处是可以轻松地扩展应用程序,而无需修改现有的代码。此外,工厂方法模式还可以隐藏复杂的对象创建过程,并使客户端代码更加简单和易于维护。
示例代码
package com.cxq.creational;
public class FactoryMethod {
public static void main(String[] args) {
PizzaFactory pizzaFactory = new CheesePizzaFactory();
PizzaFactory pizzaFactory2 = new VeggiePizzaFactory();
CheesePizza cheesePizza = (CheesePizza) pizzaFactory.createPizza();
VeggiePizza veggiePizza = (VeggiePizza) pizzaFactory2.createPizza();
}
}
abstract class Pizza {
protected String name;
public abstract void prepare();
public abstract void bake();
public abstract void cut();
public abstract void box();
public String getName() {
return name;
}
}
class CheesePizza extends Pizza {
public CheesePizza() {
name = "Cheese Pizza";
}
@Override
public void prepare() {
System.out.println("Preparing cheese pizza...");
}
@Override
public void bake() {
System.out.println("Baking cheese pizza...");
}
@Override
public void cut() {
System.out.println("Cutting cheese pizza...");
}
@Override
public void box() {
System.out.println("Boxing cheese pizza...");
}
}
class VeggiePizza extends Pizza {
public VeggiePizza() {
name = "Veggie Pizza";
}
@Override
public void prepare() {
System.out.println("Preparing veggie pizza...");
}
@Override
public void bake() {
System.out.println("Baking veggie pizza...");
}
@Override
public void cut() {
System.out.println("Cutting veggie pizza...");
}
@Override
public void box() {
System.out.println("Boxing veggie pizza...");
}
}
//
interface PizzaFactory {
Pizza createPizza();
}
//具体工厂
class CheesePizzaFactory implements PizzaFactory {
@Override
public Pizza createPizza() {
return new CheesePizza();
}
}
//具体工厂
class VeggiePizzaFactory implements PizzaFactory {
@Override
public Pizza createPizza() {
return new VeggiePizza();
}
}
抽象工厂和工厂方法的区别在于,工厂方法只能创建一个具体产品类的实例,而抽象工厂可以创建一系列的具体产品类的实例。
4 Singleton单例模式
单例模式即在系统运行中,一个类只存在一个实例,并且系统提供了一个全局访问该实例的方式。
单例模式通常用来创建系统资源、配置数据库连接等。避免创建多个实例造成的资源浪费或者同步问题。 单例模型的创建方式有两种。 双重检测锁方式
package com.cxq.creational;
public class Singleton {
private static volatile Singleton singleton;
private Singleton(){
System.out.println("创建");
}
public static Singleton getInstance(){
if(singleton== null){
synchronized (singleton){
if(singleton == null){
singleton = new Singleton();
}
}
}
return singleton;
}
}
静态内部类方式
单例模式主要适用于以下场景:
- 需要频繁使用的对象,例如数据库连接池、线程池等;
- 需要控制和管理的对象,例如系统配置、日志文件等;
- 需要避免多个实例间的冲突和资源竞争的对象,例如计数器、序列号生成器等。
在使用单例模式时,需要注意以下事项:
- 需要考虑线程安全性,可以使用双重检查锁、静态内部类等方式来保证线程安全;
- 需要注意内存泄漏的问题,可以使用弱引用、软引用等方式来避免内存泄漏;
- 需要注意反射和序列化等情况可能会破坏单例模式,可以使用枚举类型等方式来避免这种情况。
5 Prototype原型模式
原型模式允许我们通过复制对象来创建一些复杂对象。 在使用原型模式时,我们首先需要创建一个原型对象,然后将其复制多份以创建新对象。在 Java 中,原型模式的实现需要实现 Cloneable 接口,并重写 clone() 方法。
下面我们来通过一个例子更好地理解原型模式的概念和用法。假设我们有一个简单的图形类 Shape,它有一个 draw() 方法用于绘制图形。我们需要创建一个 Circle 类,它是 Shape 类的子类,并且具有不同的属性和行为。
在传统的对象创建方式中,我们需要编写一个 Circle 类,定义其属性和行为,然后在程序中实例化这个类。而使用原型模式,则可以直接复制已有的 Circle 对象,从而避免了重复编写类的过程。
public abstract class Shape implements Cloneable {
private String id;
protected String type;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
public abstract void draw();
public Object clone() {
Object clone = null;
try {
clone = super.clone();
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
return clone;
}
}
public class Circle extends Shape {
public Circle() {
type = "Circle";
}
@Override
public void draw() {
System.out.println("Drawing a circle");
}
}
public class PrototypePatternDemo {
public static void main(String[] args) {
Circle circle = new Circle();
circle.setId("1");
Circle clonedCircle = (Circle) circle.clone();
clonedCircle.setId("2");
System.out.println("Original object: " + circle.getType() + ", ID: " + circle.getId());
System.out.println("Cloned object: " + clonedCircle.getType() + ", ID: " + clonedCircle.getId());
}
}
原型模式的优点在于它能够提高程序的效率,因为对象的创建通常比对象的复制更加耗费时间和资源。此外,原型模式还能够提高代码的灵活性,因为它允许我们动态地添加、删除和修改对象。