Java设计模式是一组在解决软件设计中常见问题时的经验总结,它们是可重用的解决方案模板,旨在提高代码的可维护性、灵活性和可扩展性。
一、设计模式可以分为三大类
1、创建型模式(Creational Patterns)
1.1、工厂方法模式(Factory Method)
定义一个创建对象的接口,让子类决定实例化哪一个类。
interface Shape {void draw();
}class Rectangle implements Shape {@Overridepublic void draw() {System.out.println("Inside Rectangle::draw() method.");}
}class Square implements Shape {@Overridepublic void draw() {System.out.println("Inside Square::draw() method.");}
}class ShapeFactory {public Shape getShape(String shapeType){if(shapeType == null){return null;} if(shapeType.equalsIgnoreCase("RECTANGLE")){return new Rectangle();} else if(shapeType.equalsIgnoreCase("SQUARE")){return new Square();}return null;}
}
1.2、抽象工厂模式(Abstract Factory)
提供一个创建一系列相关或相互依赖对象的接口,而无需指定它们的具体类。
//假设我们有一个系统需要创建不同类型的GUI组件(按钮和文本框),并且这些组件有多种风格(Windows风格和MacOS风格)。
//首先,定义两个接口,分别代表按钮和文本框:
// GUI组件接口
interface Button {void paint();
}interface TextBox {void render();
}//然后,为每种风格实现这些接口:
// Windows风格的组件
class WindowsButton implements Button {@Overridepublic void paint() {System.out.println("Rendering a Windows button.");}
}class WindowsTextBox implements TextBox {@Overridepublic void render() {System.out.println("Rendering a Windows text box.");}
}// MacOS风格的组件
class MacOSButton implements Button {@Overridepublic void paint() {System.out.println("Rendering a MacOS button.");}
}class MacOSTextBox implements TextBox {@Overridepublic void render() {System.out.println("Rendering a MacOS text box.");}
}//接下来,定义抽象工厂接口和具体工厂类:
// 抽象工厂接口
interface GUIFactory {Button createButton();TextBox createTextBox();
}// Windows风格的工厂
class WindowsFactory implements GUIFactory {@Overridepublic Button createButton() {return new WindowsButton();}@Overridepublic TextBox createTextBox() {return new WindowsTextBox();}
}// MacOS风格的工厂
class MacOSFactory implements GUIFactory {@Overridepublic Button createButton() {return new MacOSButton();}@Overridepublic TextBox createTextBox() {return new MacOSTextBox();}
}//最后,客户端代码可以根据需要选择工厂来创建组件:
public class Client {public static void main(String[] args) {// 根据操作系统选择工厂GUIFactory factory;if (System.getProperty("os.name").contains("Windows")) {factory = new WindowsFactory();} else {factory = new MacOSFactory();}// 创建组件并渲染Button button = factory.createButton();button.paint();TextBox textBox = factory.createTextBox();textBox.render();}
}/**
在这个例子中,GUIFactory是一个抽象工厂,它声明了创建GUI组件的接口,而WindowsFactory和MacOSFactory是具体工厂,它们实现了这些接口,用于创建特定风格的组件。客户端代码通过选择合适的工厂来获取与平台相匹配的组件实例,而无需直接关心具体类的创建细节。
**/
1.3、单例模式(Singleton)
保证一个类只有一个实例,并提供一个全局访问点。
public class Singleton {private static volatile Singleton instance;private Singleton() {}public static Singleton getInstance() {if (instance == null) {synchronized (Singleton.class) {if (instance == null) {instance = new Singleton();}}}return instance;}
}
1.4、建造者模式(Builder)
将一个复杂对象的构建与其表示分离,使得同样的构建过程可以创建不同的表示。
/**
建造者模式(Builder Pattern)用于创建复杂的对象,它将对象的构造过程和表示分离,使得构造过程可以有不同的表示。下面是一个简单的Java建造者模式示例,以创建一个汉堡包(Hamburger)为例:
首先,我们定义一个Hamburger类,它代表最终要构建的产品:
**/
public class Hamburger {private String bread;private String patty;private String sauce;private String cheese;public Hamburger(String bread, String patty, String sauce, String cheese) {this.bread = bread;this.patty = patty;this.sauce = sauce;this.cheese = cheese;}@Overridepublic String toString() {return "Hamburger{" +"bread='" + bread + '\'' +", patty='" + patty + '\'' +", sauce='" + sauce + '\'' +", cheese='" + cheese + '\'' +'}';}
}//接着,定义一个HamburgerBuilder接口,它声明了构建汉堡的各个步骤:
public interface HamburgerBuilder {HamburgerBuilder withBread(String bread);HamburgerBuilder withPatty(String patty);HamburgerBuilder withSauce(String sauce);HamburgerBuilder withCheese(String cheese);Hamburger build();
}
//现在,我们可以创建一个具体的VeggieHamburgerBuilder类,实现HamburgerBuilder接口:
public class VeggieHamburgerBuilder implements HamburgerBuilder {private String bread;private String patty;private String sauce;private String cheese;@Overridepublic HamburgerBuilder withBread(String bread) {this.bread = bread;return this;}@Overridepublic HamburgerBuilder withPatty(String patty) {this.patty = patty;return this;}@Overridepublic HamburgerBuilder withSauce(String sauce) {this.sauce = sauce;return this;}@Overridepublic HamburgerBuilder withCheese(String cheese) {this.cheese = cheese;return this;}@Overridepublic Hamburger build() {return new Hamburger(bread, patty, sauce, cheese);}
}//最后,我们可以创建一个Director类来指导如何使用建造者
public class Director {public Hamburger construct(HamburgerBuilder builder) {return builder.withBread("Whole Wheat").withPatty("Vegetable Patty").withSauce("Tomato Sauce").withCheese("No Cheese") // Vegetarian option.build();}
}
//客户端代码可以这样使用上述类:
public class Client {public static void main(String[] args) {HamburgerBuilder builder = new VeggieHamburgerBuilder();Director director = new Director();Hamburger veggieHamburger = director.construct(builder);System.out.println(veggieHamburger);}
}
/**
在这个例子中,Director类负责组织建造者的构建步骤,而VeggieHamburgerBuilder则负责具体构建Hamburger对象。这种方式允许我们在不修改Director或Hamburger的情况下,添加新的汉堡类型(如ChickenHamburgerBuilder)。
**/
1.5、原型模式(Prototype)
用原型实例指定创建对象的种类,并通过复制这些原型创建新的对象。
/**
定义原型接口(可选)
定义一个原型接口来规范所有的原型对象都必须实现clone()方法。
**/
public interface Prototype {Prototype clone();
}/**
实现原型类
接下来,创建一个实现了Cloneable接口并实现了Prototype接口的具体原型类。
这里以一个简单的Shape类为例,假设我们有圆形、方形等形状,它们都可以被复制。
**/
import java.util.Date;public class Shape implements Cloneable, Prototype {private String id;private Date createdOn;public Shape() {this.createdOn = new Date();}// Getter and Setter methods for id and createdOn@Overridepublic Prototype clone() {try {return (Prototype) super.clone();} catch (CloneNotSupportedException e) {throw new AssertionError("Clone should be supported", e);}}
}// 具体的形状类,如 Circle 和 Square,继承自 Shape 类并添加各自的属性和方法
class Circle extends Shape {private int radius;// Constructor, getters, and setters for radius
}class Square extends Shape {private int side;// Constructor, getters, and setters for side
}/**
客户端代码
客户端代码使用原型对象的clone()方法来创建新的对象实例。
**/
public class Client {public static void main(String[] args) {Circle circle = new Circle();circle.setId("1");circle.setRadius(5);Circle clonedCircle = (Circle) circle.clone();System.out.println("Original Circle ID: " + circle.getId());System.out.println("Cloned Circle ID: " + clonedCircle.getId());// 注意:尽管ID相同,但它们是两个不同的对象,createdOn时间也会不同}
}
2、结构型模式(Structural Patterns)
2.1、适配器模式(Adapter)
将一个类的接口转换成客户希望的另一个接口,使得原本不兼容的类可以一起工作。
这种模式涉及到一个单一的类,该类负责加入独立接口到另一个接口中,使得两者能够协同工作。
下面是一个简单的Java适配器模式示例:
/**
*** 其中有一个音频播放器只能播放.mp3文件,但希望它也能播放.wav文件。
*** 为此,创建一个适配器来让.wav文件看起来像.mp3文件。
**///目标接口(Target Interface)// 客户端已经期待的接口,即播放器能识别的音频格式
interface MediaPlayer {void play(String audioType, String fileName);
}//适配者类(Adaptee Class)// 现有的音频播放类,只能播放.wav文件
class AudioPlayer implements MediaPlayer {@Overridepublic void play(String audioType, String fileName) {if ("mp3".equalsIgnoreCase(audioType)) {System.out.println("AudioPlayer cannot play this type of file: " + audioType);} else if ("wav".equalsIgnoreCase(audioType)) {System.out.println("Playing wav file. Name: " + fileName);}}
}//适配器类(Adapter Class)// 适配器类,使AudioPlayer能够播放.mp3文件
class MediaAdapter implements MediaPlayer {private final AudioPlayer audioPlayer;public MediaAdapter(AudioPlayer audioPlayer) {this.audioPlayer = audioPlayer;}@Overridepublic void play(String audioType, String fileName) {if ("mp3".equalsIgnoreCase(audioType)) {// 将.mp3文件转换为.wav格式,然后调用AudioPlayer的play方法fileName = fileName.replace(".mp3", ".wav");audioPlayer.play("wav", fileName);} else {audioPlayer.play(audioType, fileName);}}
}//客户端代码(Client Code)
public class AdapterPatternDemo {public static void main(String[] args) {AudioPlayer audioPlayer = new AudioPlayer();// 使用适配器播放.mp3文件MediaPlayer mediaAdapter = new MediaAdapter(audioPlayer);mediaAdapter.play("mp3", "song.mp3");