网站建设培训的心得成都最好的seo外包
目录
- 创建型模式
- 简单工厂
- 工厂方法
- 抽象工厂
- 建造者模式
- 单例模式
创建型模式
简单工厂
介绍:
简单工厂是一种编程习惯,也是一种建造型设计模式,提供了一种对象创建方式,无需向客户端暴露对象创建逻辑,只需要知道接口,即可创建不同的对象。
例子:
假设我们要创建不同类型的形状(如圆形、矩形等),我们可以使用简单工厂模式来实现。
Shape接口
public interface Shape {void draw();
}
Circle类
public class Circle implements Shape {@Overridepublic void draw() {System.out.println("Drawing a Circle");}
}
Rectangle类
public class Rectangle implements Shape {@Overridepublic void draw() {System.out.println("Drawing a Rectangle");}
}
ShapeFactory类
public class ShapeFactory {// 使用 getShape 方法获取形状类型的对象public static Shape getShape(String shapeType) {if (shapeType == null) {return null;}if (shapeType.equalsIgnoreCase("CIRCLE")) {return new Circle();} else if (shapeType.equalsIgnoreCase("RECTANGLE")) {return new Rectangle();}return null;}
}
客户端代码
public class Client {public static void main(String[] args) {Shape shape1 = ShapeFactory.getShape("CIRCLE");shape1.draw();Shape shape2 = ShapeFactory.getShape("RECTANGLE");shape2.draw();}
}
UML图
优点
降低耦合度:将逻辑代码封装到工厂类中,客户端不需要知道创建的逻辑,只需要调用工厂方法即可,降低客户端的耦合度。
提高可扩展性:后续需要添加产品,只需要在工厂类扩展即可,不需要修改客户端代码,符合开闭原则。
缺点
一定程度上违反开闭原则:虽然简化了客户端代码,但是需要扩展的时候还是需要修改工厂类的逻辑,在一定程度上违反了开闭原则。
工厂类职责过重:随着类型的增加,导致工厂的代码逻辑越来越重。
工厂方法
介绍:
工厂方法模式是一种创建型设计模式,提供 ··············了一个创建对象的接口,让子类(具体工厂)决定创建的对象。后续如果有型对象新增时,只需要新增具体工厂类和具体产品即可,不需要修改原来的代码,符合开闭原则。
角色·······························
产品接口:定义产品的规范,所有具体产品类都必须实现该接口。
具体产品类:实现了产品接口的具体类。
创建者接口:声明工厂方法,该方法返回一个产品对象。
具体创建者类:实现了创建者接口,负责实际创建具体产品类的实例。
例子
假设我们要创建不同类型的交通工具(如汽车、自行车等),可以使用工厂方法模式来实现。
产品接口
// 产品接口
public interface Vehicle {void drive();
}
具体产品类
// 具体产品类 - 汽车
public class Car implements Vehicle {@Overridepublic void drive() {System.out.println("Driving a Car");}
}// 具体产品类 - 自行车
public class Bicycle implements Vehicle {@Overridepublic void drive() {System.out.println("Riding a Bicycle");}
}
创建者接口
// 创建者接口
public abstract class VehicleFactory {// 工厂方法public abstract Vehicle createVehicle();
}
具体创建者类
// 具体创建者类 - 汽车工厂
public class CarFactory extends VehicleFactory {@Overridepublic Vehicle createVehicle() {return new Car();}
}// 具体创建者类 - 自行车工厂
public class BicycleFactory extends VehicleFactory {@Overridepublic Vehicle createVehicle() {return new Bicycle();}
}
客户端代码
public class Client {public static void main(String[] args) {// 创建汽车工厂并生产汽车VehicleFactory carFactory = new CarFactory();Vehicle car = carFactory.createVehicle();car.drive();// 创建自行车工厂并生产自行车VehicleFactory bicycleFactory = new BicycleFactory();Vehicle bicycle = bicycleFactory.createVehicle();bicycle.drive();}
}
UML
优点
开闭原则:新产品的添加不需要修改原有代码,符合开闭原则。
提高灵活性和可扩展性:客户端可以根据不同需求选择不同工厂创建对象。
职责单一:每一个类只负责创建一种产品。
缺点
类爆炸:随着系统的维护,类会越来越多,增加系统复杂性。
客户端需要了解工厂类:客户端需要知道创建的对象使用哪一个工厂创建。
抽象工厂
介绍
抽象工厂是一种创建型设计模式,提供了一个接口,用于创建一系类相关或相互依赖的对象,不需要指定具体的类。通常定义一个抽象工厂接口,由实现类决定创建的具体产品族
角色
抽象产品接口:定义每一类产品的规范,所有具体产品类都必须实现这些接口。
具体产品类:实现了抽象产品接口的具体类,通常每个具体工厂类会创建一组具体的产品。
抽象工厂接口:声明创建一系列相关产品的方法。
具体工厂类:实现了抽象工厂接口,负责实际创建具体的产品族。
例子
抽象产品接口
// 抽象产品接口 - 按钮
public interface Button {void render();
}// 抽象产品接口 - 复选框
public interface Checkbox {void render();
}
具体产品类
// 具体产品类 - Windows按钮
public class WindowsButton implements Button {@Overridepublic void render() {System.out.println("Rendering a Windows button.");}
}// 具体产品类 - Mac按钮
public class MacButton implements Button {@Overridepublic void render() {System.out.println("Rendering a Mac button.");}
}// 具体产品类 - Windows复选框
public class WindowsCheckbox implements Checkbox {@Overridepublic void render() {System.out.println("Rendering a Windows checkbox.");}
}// 具体产品类 - Mac复选框
public class MacCheckbox implements Checkbox {@Overridepublic void render() {System.out.println("Rendering a Mac checkbox.");}
}
抽象工厂接口
// 抽象工厂接口
public interface GUIFactory {Button createButton();Checkbox createCheckbox();
}
具体工厂类
// 具体工厂类 - Windows工厂
public class WindowsFactory implements GUIFactory {@Overridepublic Button createButton() {return new WindowsButton();}@Overridepublic Checkbox createCheckbox() {return new WindowsCheckbox();}
}// 具体工厂类 - Mac工厂
public class MacFactory implements GUIFactory {@Overridepublic Button createButton() {return new MacButton();}@Overridepublic Checkbox createCheckbox() {return new MacCheckbox();}
}
客户端代码
public class Client {private Button button;private Checkbox checkbox;public Client(GUIFactory factory) {button = factory.createButton();checkbox = factory.createCheckbox();}public void renderUI() {button.render();checkbox.render();}public static void main(String[] args) {// 创建Windows主题的UIGUIFactory windowsFactory = new WindowsFactory();Client windowsClient = new Client(windowsFactory);windowsClient.renderUI();// 创建Mac主题的UIGUIFactory macFactory = new MacFactory();Client macClient = new Client(macFactory);macClient.renderUI();}
}
UML
抽象工厂和工厂方法的区别
- 目的:工厂方法模式,定义一个创建单一产品对象的接口,让子类决定具体的实例化对象,抽象工厂方法模式,定义一个接口,用户创建一系类相关或相互依赖的接口,不需要指定他们具体的类。
- 关注点:工厂方法模式关注单一产品,抽象工厂模式关注一整套相关产品。
建造者模式
介绍
建造者模式是一种创建型设计模式,他允许你分步骤的创建一个复杂对象,它的目的是让一个复杂对象的构建和表示进行分离,使得不同的构建过程能够的到不同的表示。
例如我要配置一台电脑,我有好几个方案,方案一是配置为(4060显卡,32G内存,1T硬盘空间),方案二是配置为(3050显卡,16G内存,512G硬盘空间),我根据我的需要告诉装机师傅,我要按照什么方案配置,按照方案一配置一台性能好的电脑,按照方案二配置一台性能弱一点的电脑,我的电脑就是产品,方案就是具体建造者,师傅就是指挥者,这个过程实现了构建与表示分离,可以根据不同的构建方案出现不同的表示(电脑)。
角色
- 产品:一个复杂的对象
- 抽象建造者:定义了创建复杂产品个个内容的抽象方法。
- 具体建造者:实现了抽象建造者的接口,有它决定每一个内容的具体创建
- 指挥者:由他嗲用建造者的方法,决定整个构建过程。
例子
// 产品类:电脑
class Computer {private String cpu;private String memory;private String hardDisk;public void setCpu(String cpu) {this.cpu = cpu;}public void setMemory(String memory) {this.memory = memory;}public void setHardDisk(String hardDisk) {this.hardDisk = hardDisk;}@Overridepublic String toString() {return "CPU: " + cpu + ", Memory: " + memory + ", Hard Disk: " + hardDisk;}
}// 抽象建造者类
abstract class ComputerBuilder {protected Computer computer;public ComputerBuilder() {this.computer = new Computer();}public abstract void setCPU(String cpu);public abstract void setMemory(String memory);public abstract void setHardDisk(String hardDisk);public Computer getComputer() {return computer;}
}// 具体建造者类:组装特定配置的电脑
class GamingComputerBuilder extends ComputerBuilder {@Overridepublic void setCPU(String cpu) {computer.setCpu(cpu);}@Overridepublic void setMemory(String memory) {computer.setMemory(memory);}@Overridepublic void setHardDisk(String hardDisk) {computer.setHardDisk(hardDisk);}
}// 指挥者类
class Director {private ComputerBuilder builder;public Director(ComputerBuilder builder) {this.builder = builder;}public Computer constructComputer() {builder.setCPU("Intel i9");builder.setMemory("32GB");builder.setHardDisk("1TB SSD");return builder.getComputer();}
}// 主类,测试建造者模式
public class BuilderPatternExample {public static void main(String[] args) {// 创建具体建造者GamingComputerBuilder gamingBuilder = new GamingComputerBuilder();// 创建指挥者,并传入具体建造者Director director = new Director(gamingBuilder);// 指挥者构建电脑Computer gamingComputer = director.constructComputer();System.out.println(gamingComputer);}
}
UML
单例模式
介绍
单例模式是一种创建型的设计模式,确保一个类只有一个实例化对象,并提供一个全局访问点,访问该对象。
饿汉模式
在类加载的时候初始化对象。
// 饿汉式单例模式
public class EagerSingleton {// 在类加载时就创建好单例对象private static final EagerSingleton INSTANCE = new EagerSingleton();// 私有构造函数,防止外部通过 new 创建实例private EagerSingleton() {}// 提供一个全局访问点public static EagerSingleton getInstance() {return INSTANCE;}
}
优点:实现简单,线程安全。
缺点:如果对象占用资源很多,一开始实例化又不使用,占用大量资源。
懒汉模式(非线程安全)
在类第一次调用的时候再初始化。
// 懒汉式单例模式(非线程安全)
public class LazySingleton {private static LazySingleton INSTANCE;private LazySingleton() {}public static LazySingleton getInstance() {if (INSTANCE == null) {INSTANCE = new LazySingleton();}return INSTANCE;}
}
懒汉式单例(线程安全,加锁)
// 懒汉式单例模式(线程安全,加锁)
public class ThreadSafeLazySingleton {private static ThreadSafeLazySingleton INSTANCE;private ThreadSafeLazySingleton() {}public static synchronized ThreadSafeLazySingleton getInstance() {if (INSTANCE == null) {INSTANCE = new ThreadSafeLazySingleton();}return INSTANCE;}
}
双重检查锁(DCL)单例
// 双重检查锁单例模式
public class DclSingleton {// 使用 volatile 关键字保证可见性和禁止指令重排private static volatile DclSingleton INSTANCE;private DclSingleton() {}public static DclSingleton getInstance() {if (INSTANCE == null) {synchronized (DclSingleton.class) {if (INSTANCE == null) {INSTANCE = new DclSingleton();}}}return INSTANCE;}
}
了解一下volatile
什么是volatile:它是一个修饰符,用于修饰变量,它有以下两种功能。
- 可见性:被它修饰的变量,被修改时,新值可以马上别其他线程看到
- 禁止指令重排序:编译器和处理器为了提高效率,可能会将指令重新编排,导致意想不到的错误,使用了这个修饰符,可以禁止指令重新编排
为什么要只用volatile
举个例子,在执行new DclSingleton()的时候,会有以下几个步骤:
- 分配内存
- 初始化对象
- 设置默认值
- 执行构造器
- 将INSTANCE指向分配的内存地址
由于指令重排序,步骤2,3可能会被重排序,先将INSTANCE指向分配的内存地址,在初始化对象
线程A先执行将INSTANCE指向分配的内存地址,这个时候还没有初始化对象,线程B判断这个对象已经指向一个地址了,不为null,放回一个未初始化的对象,导致程序出现问题。