前言:
都知道Java有23种设计模式,但实际开发中相信很多同学基本很少能利用上这些设计模式.
下面我将结合实际开发应用场景来进行简单解读一下这些设计模式在实际开发中是怎么使用的.
1.单例模式(Singleton)
确保一个类只有一个实例,并提供一个全局访问点。它又分为饿汉式和懒汉式; 一般会在数据库连接池、线程池、配置管理器使用这玩意.
a.饿汉式(静态常量)
饿汉式在类加载时就完成了初始化,所以是线程安全的,但可能会造成内存浪费,比如该实例一直没被使用.
public class SingletonHungry {
// 创建 SingletonHungry 的一个对象
private static final SingletonHungry instance = new SingletonHungry();
// 让构造函数为 private,这样该类就不会被实例化
private SingletonHungry(){}
// 获取唯一可用的对象
public static SingletonHungry getInstance(){
return instance;
}
}
b.懒汉式
懒汉式在第一次调用 getInstance() 方法时才初始化实例,实现了延迟加载,但是上面的简单实现不是线程安全的。为了保证线程安全,可以使用 synchronized 关键字对 getInstance() 方法进行同步。
public class SingletonLazy {
private static SingletonLazy instance;
private SingletonLazy(){}
public static synchronized SingletonLazy getInstance(){
if(instance == null){
instance = new SingletonLazy();
}
return instance;
}
}
c.上面这种肯定效率低,因为是同步并且为了线程安全加了synchronized ,优化一下
public class SingletonLazy {
private volatile static SingletonLazy instance;
private SingletonLazy(){}
public static SingletonLazy getInstance(){
// 第一次检查:如果实例不存在
if(instance == null){
synchronized (SingletonLazy.class){ // 加锁
if(singleton == null){ // 第二次检查:进入该代码块前可能已经有其他线程创建了实例
singleton = new SingletonLazy();
}
}
}
return singleton;
}
}
2.工厂方法模式(Factory Method)
概念:
它定义了一个用于创建对象的接口,但让子类决定实例化哪一个类。工厂方法使一个类的实例化延迟到其子类。这种模式非常适合于当一个类不知道它所必须创建的对象的类的时候,即客户端不需要知道具体产品类的类名,只需要知道所对应的工厂即可,使得系统可以在不修改具体产品类的情况下增加新产品。
实际使用场景:
假设我们正在开发一个应用程序,该程序需要处理不同类型的日志记录(例如:文本日志、数据库日志),我们可以使用工厂方法模式来根据需要创建不同的日志记录器对象.
直接上代码:
a.定义日志记录器接口
public interface Logger {
void log(String message);
}
b.实现具体日志记录器
public class TextLogger implements Logger {
@Override
public void log(String message) {
System.out.println("Text Log: " + message);
}
}
public class DatabaseLogger implements Logger {
@Override
public void log(String message) {
System.out.println("Database Log: " + message);
}
}
c.定义日志记录器工厂接口及具体工厂
public interface LoggerFactory {
Logger createLogger();
}
public class TextLoggerFactory implements LoggerFactory {
@Override
public Logger createLogger() {
return new TextLogger();
}
}
public class DatabaseLoggerFactory implements LoggerFactory {
@Override
public Logger createLogger() {
return new DatabaseLogger();
}
}
d.客户端代码
public class Client {
public static void main(String[] args) {
// 文本日志
LoggerFactory textFactory = new TextLoggerFactory();
Logger textLogger = textFactory.createLogger();
textLogger.log("This is a text log message.");
// 数据库日志
LoggerFactory dbFactory = new DatabaseLoggerFactory();
Logger dbLogger = dbFactory.createLogger();
dbLogger.log("This is a database log message.");
}
}
3.抽象工厂模式(Abstract Factory)
概念:
它提供一个创建一系列相关或相互依赖对象的接口,而无需指定它们具体的类。这种模式适合于一个系统要独立于产品的创建、组合和表示时。与工厂方法模式相比,抽象工厂模式生产的是产品族,而不是单一的产品。
实际使用场景:
假设我们正在开发一个跨平台的应用程序,该程序需要在Windows、MacOS、Linux等不同操作系统上运行,并且每个平台上都有不同的按钮和对话框风格。为了实现界面组件的平台无关性,我们可以使用抽象工厂模式来创建与特定平台相关的UI组件。
直接上代码:
a.抽象产品接口
public interface Button {
void paint();
}
public interface Dialog {
void draw();
}
b.具体产品类
// Windows风格的UI组件
public class WindowsButton implements Button {
@Override
public void paint() {
System.out.println("Painting a Windows button.");
}
}
public class WindowsDialog implements Dialog {
@Override
public void draw() {
System.out.println("Drawing a Windows dialog.");
}
}
// MacOS风格的UI组件
public class MacOSButton implements Button {
@Override
public void paint() {
System.out.println("Painting a MacOS button.");
}
}
public class MacOSDialog implements Dialog {
@Override
public void draw() {
System.out.println("Drawing a MacOS dialog.");
}
}
c.抽象工厂接口
public interface GUIFactory {
Button createButton();
Dialog createDialog();
}
d.具体工厂类
public class WindowsFactory implements GUIFactory {
@Override
public Button createButton() {
return new WindowsButton();
}
@Override
public Dialog createDialog() {
return new WindowsDialog();
}
}
public class MacOSFactory implements GUIFactory {
@Override
public Button createButton() {
return new MacOSButton();
}
@Override
public Dialog createDialog() {
return new MacOSDialog();
}
}
e.客户端代码
public class Application {
public static void main(String[] args) {
// 假设从配置中读取到当前平台信息
String platform = detectPlatform(); // 实际应用中可能通过系统属性判断
GUIFactory factory;
if ("Windows".equals(platform)) {
factory = new WindowsFactory();
} else if ("MacOS".equals(platform)) {
factory = new MacOSFactory();
} else {
throw new IllegalArgumentException("Unsupported platform: " + platform);
}
Button button = factory.createButton();
Dialog dialog = factory.createDialog();
button.paint();
dialog.draw();
}
// 简化的平台检测逻辑
private static String detectPlatform() {
// 这里仅作为示例,真实环境中可能通过System.getProperty("os.name")等方式检测
return "Windows";
}
}
4.建造者模式(Builder)
概念:
它允许用户通过一步步构造(或一步一步设置属性)的方式创建复杂的对象,而这个构建过程通常是可变的,可以创建不同表现形式的对象。该模式将构建复杂对象的过程与它的表示分离,使得同样的构建过程可以创建不同的表示。
实际使用场景:
设想一个软件开发项目中,需要创建不同配置的电脑(Computer),比如游戏电脑、办公电脑等,每种类型的电脑有不同的硬件配置,如CPU型号、内存大小、硬盘类型等。使用建造者模式可以灵活地创建这些不同配置的电脑,而不需要为每一种配置创建一个单独的类。
直接上代码:
a.抽象产品(Product)
@Data
public class Computer {
private String cpu;
private int ram;
private String hdd;
private boolean hasGraphicsCard;
public Computer(String cpu, int ram, String hdd, boolean hasGraphicsCard) {
this.cpu = cpu;
this.ram = ram;
this.hdd = hdd;
this.hasGraphicsCard = hasGraphicsCard;
}
}
b.抽象建造者(Builder)
public interface ComputerBuilder {
ComputerBuilder setCpu(String cpu);
ComputerBuilder setRam(int ram);
ComputerBuilder setHdd(String hdd);
ComputerBuilder setGraphicsCard(boolean hasGraphicsCard);
Computer build();
}
c.具体建造者(Concrete Builder)
public class GamingComputerBuilder implements ComputerBuilder {
private String cpu;
private int ram;
private String hdd;
private boolean hasGraphicsCard;
@Override
public ComputerBuilder setCpu(String cpu) {
this.cpu = cpu;
return this;
}
@Override
public ComputerBuilder setRam(int ram) {
this.ram = ram;
return this;
}
@Override
public ComputerBuilder setHdd(String hdd) {
this.hdd = hdd;
return this;
}
@Override
public ComputerBuilder setGraphicsCard(boolean hasGraphicsCard) {
this.hasGraphicsCard = true; // 游戏电脑默认有显卡
return this;
}
@Override
public Computer build() {
return new Computer(cpu, ram, hdd, hasGraphicsCard);
}
}
// 可以为其他类型(如OfficeComputerBuilder)定义类似的实现
d.指挥者(Director)
public class ComputerDirector {
public Computer constructGamingComputer(ComputerBuilder builder) {
return builder
.setCpu("Intel i9")
.setRam(32)
.setHdd("SSD 1TB")
.build();
}
}
e.客户端代码
public class Client {
public static void main(String[] args) {
ComputerBuilder builder = new GamingComputerBuilder();
ComputerDirector director = new ComputerDirector();
Computer gamingComputer = director.constructGamingComputer(builder);
System.out.println(gamingComputer); // 实际使用中可能需要重写Computer的toString方法以输出有意义的信息
}
}
5.原型模式(Prototype)
概念:
它允许创建对象的副本,而无需了解对象的具体类或重新初始化它们。这种模式特别适用于当创建新对象的成本较高时,或者对象的初始化过程复杂且实例化次数不确定的情况。通过克隆已有对象,可以快速得到新的对象实例,且新对象状态可以基于原有对象进行调整。
实际使用场景:
假设在一个图形编辑软件中,用户可以创建各种形状(如圆形、矩形等)并对其进行编辑。当用户需要创建多个相似形状时,直接复制现有形状并稍作修改比每次都从头创建新形状更为高效。这时就可以利用原型模式来实现这一功能。
直接上代码:
a.抽象原型接口
public interface ShapePrototype {
ShapePrototype clone();
void draw();
}
b.具体原型类
public class Circle implements ShapePrototype {
private int radius;
private String color;
public Circle(int radius, String color){
this.radius = radius;
this.color = color;
}
@Override
public ShapePrototype clone() {
return new Circle(radius, color);
}
@Override
public void draw() {
System.out.println("Drawing Circle with radius: " + radius + " and color: " + color);
}
}
public class Rectangle implements ShapePrototype {
private int width;
private int height;
private String color;
public Rectangle(int width, int height, String color){
this.width = width;
this.height = height;
this.color = color;
}
@Override
public ShapePrototype clone() {
return new Rectangle(width, height, color);
}
@Override
public void draw() {
System.out.println("Drawing Rectangle with width: " + width + ", height: " + height + ", and color: " + color);
}
}
c.客户端代码
public class PrototypePatternDemo {
public static void main(String[] args) {
ShapePrototype circlePrototype = new Circle(5, "Blue");
ShapePrototype clonedCircle = circlePrototype.clone();
clonedCircle.draw(); // 输出圆形绘制信息
ShapePrototype rectanglePrototype = new Rectangle(10, 20, "Red");
ShapePrototype clonedRectangle = rectanglePrototype.clone();
clonedRectangle.draw(); // 输出矩形绘制信息
}
}
好了以上就是创建型设计模式的几种具体设计模式的使用场景;下期见.