设计模式包含创建、结构型和行为型。
本文按照类型,罗列了一些常见的设计模式,给出了基本的定义,和代码案例。
后续会不断的优化定义,代码。
创建型设计模式
创建型设计模式主要用来处理对象的创建过程,并封装复杂的实力化逻辑。它的主要作用是提供一种灵活的方法来创建对象,使得代码可维护和可扩展。
单例模式
定义:确保一个类只有一个实例
优点:节省系统资源,方便对实例进行控制
应用场景:适用于那些需要确保只有一个实例的情况,比如系统配置的存储
饿汉式
在类加载的时候就创建实例,并提供一个公共的静态方法来访问该实例。不存在并发问题。但是会浪费一些资源。
public class Singleton {
private static Singleton instance = new Singleton();
private Singleton() {}
public static Singleton getInstance() {
return instance;
}
}
懒汉式
需要时才创建对象,但是会有并发问题。可以使用synchronized或者双重检查锁定实现线程安全。
//懒汉式,线程安全,但加锁影响性能
public class Singleton {
private static Singleton instance;
private Singleton() {}
public static synchronized Singleton getInstance() {
if (instance == null) {
instance = new Singleton();
}
return instance;
}
}
//懒汉式,线程安全且性能好,双重检查锁定
public class Singleton {
private volatile static Singleton instance;
private Singleton() {}
public static Singleton getInstance() {
if (instance == null) {
synchronized (Singleton.class) {
if (instance == null) {
instance = new Singleton();
}
}
}
return instance;
}
}
静态内部类
利用Java的类加载机制实现懒加载,静态内部类只有在被调用时才会加载,静态内部类是私有的,只有在调用getInstance()方法时才会被加载,因此可以实现懒加载和线程安全。不浪费资源。
public class Singleton {
private Singleton() {}
private static class SingletonHolder {
private static final Singleton INSTANCE = new Singleton();
}
public static Singleton getInstance() {
return SingletonHolder.INSTANCE;
}
}
枚举
利用枚举类型的特性实现单例模式,保证只有一个实例,并且不会被反射破坏。
public enum Singleton {
INSTANCE;
public void doSomething() {
//do something
}
}
工厂模式
定义:定义一个用于创建对象的接口,让子类来决定要实例化哪个类。
优点:增加新产品时不需要修改既有代码,只需添加新的工厂类即可。
应用场景:适用于需要根据不同的条件创建不同的对象的情况,如数据库连接池的实现。
实现
一般工厂模式
● 创建接口或抽象类,用于定义工厂方法和产品方法。
// 抽象产品接口
public interface Product {
void use();
}
// 抽象工厂类
public abstract class Factory {
public abstract Product createProduct();
}
● 创建具体的产品类和工厂类,实现抽象类或接口。
// 具体产品类A
public class ProductA implements Product {
@Override
public void use() {
System.out.println("Product A is used");
}
}
// 具体工厂类A
public class FactoryA extends Factory {
@Override
public Product createProduct() {
return new ProductA();
}
}
// 具体产品类B
public class ProductB implements Product {
@Override
public void use() {
System.out.println("Product B is used");
}
}
// 具体工厂类B
public class FactoryB extends Factory {
@Override
public Product createProduct() {
return new ProductB();
}
}
● 在客户端中使用工厂方法创建对象。
public class Client {
public static void main(String[] args) {
Factory factory = new FactoryA();
Product product = factory.createProduct();
product.use(); // Product A is used
factory = new FactoryB();
product = factory.createProduct();
product.use(); // Product B is used
}
}
除了一般工厂模式,还有简单工厂模式和抽象工厂模式
简单工厂
又称为静态工厂模式,通过一个工厂类,根据传入的参数动态决定创建哪一个产品类的实例。这种模式违背了开闭原则,因为每增加一个产品类就需要修改工厂类的代码。
public class SimpleFactory {
public static Product createProduct(String type) {
if (type.equals("A")) {
return new ProductA();
} else if (type.equals("B")) {
return new ProductB();
} else {
throw new IllegalArgumentException("Invalid product type: " + type);
}
}
}
抽象工厂模式
一般工厂模式适用于需要创建单个产品对象的场景,而抽象工厂模式适用于需要创建一组相关或相互依赖的产品对象的场景。
● 定义抽象工厂接口,该接口定义了一系列用于创建产品对象的方法:
public interface AbstractFactory {
public ProductA createProductA();
public ProductB createProductB();
}
● 定义抽象产品接口,该接口定义了产品对象的共同属性和方法:
public interface ProductA {
public void operationA();
}
public interface ProductB {
public void operationB();
}
● 定义具体工厂实现类,实现抽象工厂接口,用于创建相关的产品对象:
public class ConcreteFactory1 implements AbstractFactory {
public ProductA createProductA() {
return new ConcreteProductA1();
}
public ProductB createProductB() {
return new ConcreteProductB1();
}
}
public class ConcreteFactory2 implements AbstractFactory {
public ProductA createProductA() {
return new ConcreteProductA2();
}
public ProductB createProductB() {
return new ConcreteProductB2();
}
}
● 定义具体产品实现类,实现抽象产品接口,用于具体实现产品的属性和方法:
public class ConcreteProductA1 implements ProductA {
public void operationA() {
System.out.println("ConcreteProductA1 operationA");
}
}
public class ConcreteProductB1 implements ProductB {
public void operationB() {
System.out.println("ConcreteProductB1 operationB");
}
}
public class ConcreteProductA2 implements ProductA {
public void operationA() {
System.out.println("ConcreteProductA2 operationA");
}
}
public class ConcreteProductB2 implements ProductB {
public void operationB() {
System.out.println("ConcreteProductB2 operationB");
}
}
● 在客户端中使用抽象工厂和具体工厂来创建产品对象:
public class Client {
public static void main(String[] args) {
AbstractFactory factory1 = new ConcreteFactory1();
ProductA productA1 = factory1.createProductA();
ProductB productB1 = factory1.createProductB();
productA1.operationA();
productB1.operationB();
AbstractFactory factory2 = new ConcreteFactory2();
ProductA productA2 = factory2.createProductA();
ProductB productB2 = factory2.createProductB();
productA2.operationA();
productB2.operationB();
}
}
建造者模式
定义:是一种创建型设计模式,它通过将一个复杂对象的构建过程分解为多个简单对象的构建过程,并将这些简单对象组合起来构建出复杂对象。
优点:可以将对象的构建过程与其表示相分离,使得同样的构建过程可以创建不同的表示,并且可以避免创建过程中的重复代码和错误,支持逐步构建复杂对象和建造者的复用。
适用场景:适用场景包括需要创建复杂对象、需要控制对象创建过程、需要支持逐步构建复杂对象等场景。
实现
首先定义一个需要被构建的复杂对象类:
public class Product {
private String partA;
private String partB;
private String partC;
public void setPartA(String partA) {
this.partA = partA;
}
public void setPartB(String partB) {
this.partB = partB;
}
public void setPartC(String partC) {
this.partC = partC;
}
public void show() {
System.out.println("Product parts: " + partA + ", " + partB + ", " + partC);
}
}
接下来定义一个建造者接口,提供构建产品所需的方法:
public interface Builder {
void buildPartA();
void buildPartB();
void buildPartC();
Product getResult();
}
接着定义具体的建造者类,实现建造者接口中的方法:
public class ConcreteBuilder implements Builder {
private Product product = new Product();
@Override
public void buildPartA() {
product.setPartA("PartA");
}
@Override
public void buildPartB() {
product.setPartB("PartB");
}
@Override
public void buildPartC() {
product.setPartC("PartC");
}
@Override
public Product getResult() {
return product;
}
}
最后定义一个指挥者类,负责指导建造过程:
public class Director {
public void construct(Builder builder) {
builder.buildPartA();
builder.buildPartB();
builder.buildPartC();
}
}
这样,我们就可以使用上述这些类来实现建造者模式了。例如:
public static void main(String[] args) {
Builder builder = new ConcreteBuilder();
Director director = new Director();
director.construct(builder);
Product product = builder.getResult();
product.show();
}
原型模式
定义:原型模式是一种创建型设计模式,它提供了一种通过复制已有对象来创建新对象的方法。
优点:避免了重复创建对象的开销,提高了性能。原因:复制已有对象的效率高,主要是因为它避免了重复创建对象的过程。在传统的对象创建方式中,每次创建一个新对象都需要对对象进行初始化和分配内存空间等操作,这些操作会消耗较多的时间和资源。而采用原型模式,可以通过复制已有对象的方式,避免了这些操作,只需要在复制对象的基础上进行一些必要的修改,就可以快速地创建新对象。这种方式相对于传统的创建对象方式,可以大大提高对象创建的效率和灵活性,特别是当对象创建的成本较高时,使用原型模式可以节省时间和资源。
适用场景:原型模式适用于需要动态地创建对象,同时又需要避免对象创建过程的耗时和内存占用问题的场景。
实现
1.创建一个实现Cloneable接口的类,这个类就是需要进行原型模式的类。
2.重写clone()方法,在方法中调用super.clone()方法,并对需要复制的属性进行赋值操作。
3.在需要复制对象的地方,调用对象的clone()方法即可得到复制后的对象。
public class Prototype implements Cloneable {
private String name;
public Prototype(String name) {
this.name = name;
}
public void setName(String name) {
this.name = name;
}
public String getName() {
return name;
}
@Override
public Prototype clone() throws CloneNotSupportedException {
return (Prototype) super.clone();
}
}
Prototype prototype1 = new Prototype("prototype1");
Prototype prototype2 = prototype1.clone();
System.out.println("prototype1 name: " + prototype1.getName()); // 输出:prototype1
System.out.println("prototype2 name: " + prototype2.getName()); // 输出:prototype1
prototype2.setName("prototype2");
System.out.println("prototype1 name: " + prototype1.getName()); // 输出:prototype1
System.out.println("prototype2 name: " + prototype2.getName()); // 输出:prototype2
结构型设计模式
用于解决在设计阶段中系统中各个类及其对象之间的组合、聚合关系问题,以实现更为灵活、可维护、可扩展的软件系统。结构型设计模式通常涉及到将类或对象进行组合以形成更大的结构,从而降低系统的复杂度。
适配器模式
定义:适配器模式通过将一个类的接口转换成另一个接口,使得原本由于接口不兼容而不能一起工作的类能够协同工作。
优点:适配器模式可以使得现有的类与新的类协同工作,从而提高程序的可复用性和可维护性。
适用场景:在系统中需要使用现有类,但是类的接口不符合系统的需求,可以考虑使用适配器模式。
实现:
1.定义目标接口:目标接口是客户端所期望的接口,它定义了客户端需要的方法。
public interface MediaPlayer {
public void play(String audioType, String fileName);
}
2.定义适配器类:适配器类实现目标接口,并持有一个适配者对象的引用。在适配器类中实现适配器方法:适配器方法调用适配者对象的方法来实现目标接口中定义的方法。
public class MediaAdapter implements MediaPlayer {
AdvancedMediaPlayer advancedMusicPlayer;
public MediaAdapter(String audioType){
if(audioType.equalsIgnoreCase("vlc") ){
advancedMusicPlayer = new VlcPlayer();
} else if (audioType.equalsIgnoreCase("mp4")){
advancedMusicPlayer = new Mp4Player();
}
}
@Override
public void play(String audioType, String fileName) {
if(audioType.equalsIgnoreCase("vlc")){
advancedMusicPlayer.playVlc(fileName);
}else if(audioType.equalsIgnoreCase("mp4")){
advancedMusicPlayer.playMp4(fileName);
}
}
}
定义适配者类:适配者类是客户端所不支持的接口,它实现了适配器类需要的方法。
public interface AdvancedMediaPlayer {
public void playVlc(String fileName);
public void playMp4(String fileName);
}
public class VlcPlayer implements AdvancedMediaPlayer{
@Override
public void playVlc(String fileName) {
System.out.println("Playing vlc file. Name: "+ fileName);
}
@Override
public void playMp4(String fileName) {
// do nothing
}
}
public class Mp4Player implements AdvancedMediaPlayer{
@Override
public void playVlc(String fileName) {
// do nothing
}
@Override
public void playMp4(String fileName) {
System.out.println("Playing mp4 file. Name: "+ fileName);
}
}
public class AudioPlayer implements MediaPlayer {
MediaAdapter mediaAdapter;
@Override
public void play(String audioType, String fileName) {
//播放 mp3 音乐文件的内置支持
if(audioType.equalsIgnoreCase("mp3")){
System.out.println("Playing mp3 file. Name: " + fileName);
}
//mediaAdapter 提供了播放其他文件格式的支持
else if(audioType.equalsIgnoreCase("vlc") || audioType.equalsIgnoreCase("mp4")){
mediaAdapter = new MediaAdapter(audioType);
mediaAdapter.play(audioType, fileName);
}
else{
System.out.println("Invalid media. " + audioType + " format not supported");
}
}
}
public class AdapterPatternDemo {
public static void main(String[] args) {
AudioPlayer audioPlayer = new AudioPlayer();
audioPlayer.play("mp3", "beyond the horizon.mp3");
audioPlayer.play("mp4", "alone.mp4");
audioPlayer.play("vlc", "far far away.vlc");
audioPlayer.play("avi", "mind me.avi");
}
}
桥接模式
定义:桥接模式将抽象部分与实现部分分离,使得它们可以独立的变化。抽象部分用于描述对象的接口,实现部分则提供具体的实现。
适用场景:当一个系统需要使用多个不同的实现方式时,可以使用桥接模式。比如对不同的操作系统使用不同的编程语言进行开发,就可以使用桥接模式将抽象部分与实现部分分离。
实现
假设有一个图形界面程序,需要绘制不同形状(圆形、矩形)和不同颜色(红色、绿色)的图形。使用桥接模式可以将形状和颜色分离,使得程序可以方便地扩展不同的形状和颜色组合。
- 定义抽象类Shape和接口Color:
public abstract class Shape {
protected Color color;
public Shape(Color color) {
this.color = color;
}
public abstract void draw();
}
public interface Color {
void fill();
}
- 定义实现类RedColor和GreenColor:
public class RedColor implements Color {
@Override
public void fill() {
System.out.println("填充红色");
}
}
public class GreenColor implements Color {
@Override
public void fill() {
System.out.println("填充绿色");
}
}
- 定义Shape的实现类Circle和Rectangle:
public class Circle extends Shape {
private int x, y, radius;
public Circle(int x, int y, int radius, Color color) {
super(color);
this.x = x;
this.y = y;
this.radius = radius;
}
@Override
public void draw() {
System.out.print("绘制圆形,");
color.fill();
}
}
public class Rectangle extends Shape {
private int x, y, width, height;
public Rectangle(int x, int y, int width, int height, Color color) {
super(color);
this.x = x;
this.y = y;
this.width = width;
this.height = height;
}
@Override
public void draw() {
System.out.print("绘制矩形,");
color.fill();
}
}
- 在客户端代码中创建不同形状和颜色的对象,并调用draw方法绘制图形:
public class Client {
public static void main(String[] args) {
Color red = new RedColor();
Color green = new GreenColor();
Shape circleRed = new Circle(100,100,50, red);
Shape circleGreen = new Circle(200,200,50, green);
Shape rectangleRed = new Rectangle(300,300,100,50, red);
Shape rectangleGreen = new Rectangle(400,400,50,100, green);
circleRed.draw();
circleGreen.draw();
rectangleRed.draw();
rectangleGreen.draw();
}
}
这里我们动态地组合了不同的抽象部分和实现部分,生成了不同的图形。如果需要添加新的图形或颜色,只需要扩展相应的抽象类和实现类即可,不会影响原有的代码,从而提高了系统的灵活性和可扩展性。
装饰器模式
定义:装饰器模式通过动态地给一个对象添加一些额外的功能,使得对象在运行时可以动态地增加或删除某些属性或行为。
适用场景:当需要增加或删除某些对象的属性或行为时,可以使用装饰器模式。比如动态地给一个文本框添加一些额外的验证规则,就可以使用装饰器模式。
// 抽象组件类
public interface Component {
void operation();
}
// 具体组件类
public class ConcreteComponent implements Component {
public void operation() {
System.out.println("ConcreteComponent operation");
}
}
// 装饰器抽象类
public abstract class Decorator implements Component {
protected Component component;
public Decorator(Component component) {
this.component = component;
}
public void operation() {
component.operation();
}
}
// 具体装饰器类A
public class ConcreteDecoratorA extends Decorator {
public ConcreteDecoratorA(Component component) {
super(component);
}
public void operation() {
super.operation();
System.out.println("ConcreteDecoratorA operation");
}
}
// 具体装饰器类B
public class ConcreteDecoratorB extends Decorator {
public ConcreteDecoratorB(Component component) {
super(component);
}
public void operation() {
super.operation();
System.out.println("ConcreteDecoratorB operation");
}
}
// 测试代码
public class Test {
public static void main(String[] args) {
Component component = new ConcreteComponent();
component = new ConcreteDecoratorA(component);
component = new ConcreteDecoratorB(component);
component.operation();
}
}
组合模式
组合模式将对象组合成树形结构,以表示“部分-整体”的层次结构。组合模式使得用户可以以相同的方式处理单个对象和组合对象。
适用场景:当需要处理树形结构的数据或者部分-整体的结构时,可以使用组合模式。
- 创建一个抽象类或接口,表示组件对象。这个类或接口可以包含添加和移除子组件、获取子组件、以及其他可以被所有组件共享的方法。
public abstract class Component {
protected String name;
public Component(String name) {
this.name = name;
}
public abstract void add(Component c);
public abstract void remove(Component c);
public abstract Component getChild(int index);
public abstract void operation();
}
- 创建一个叶子组件类,实现组件对象的接口或继承抽象类。
public class Leaf extends Component {
public Leaf(String name) {
super(name);
}
@Override
public void add(Component c) {
throw new UnsupportedOperationException("Leaf cannot add a child.");
}
@Override
public void remove(Component c) {
throw new UnsupportedOperationException("Leaf cannot remove a child.");
}
@Override
public Component getChild(int index) {
throw new UnsupportedOperationException("Leaf has no child.");
}
@Override
public void operation() {
System.out.println("Leaf " + name + " is doing something.");
}
}
- 创建一个非叶子组件类,实现组件对象的接口或继承抽象类。非叶子组件类可以包含一个或多个子组件,并实现添加、移除子组件和获取子组件的方法。
public class Composite extends Component {
private List<Component> children = new ArrayList<>();
public Composite(String name) {
super(name);
}
@Override
public void add(Component c) {
children.add(c);
}
@Override
public void remove(Component c) {
children.remove(c);
}
@Override
public Component getChild(int index) {
return children.get(index);
}
@Override
public void operation() {
System.out.println("Composite " + name + " is doing something.");
for (Component c : children) {
c.operation();
}
}
}
- 在客户端代码中,可以构建组件对象的树状结构,并通过组合模式对整个结构进行操作。
Component root = new Composite("root");
Component leaf1 = new Leaf("leaf1");
Component leaf2 = new Leaf("leaf2");
Component composite = new Composite("composite");
Component leaf3 = new Leaf("leaf3");
root.add(leaf1);
root.add(leaf2);
root.add(composite);
composite.add(leaf3);
root.operation();
输出结果如下:
Leaf leaf1 is doing something.
Leaf leaf2 is doing something.
Composite composite is doing something.
Leaf leaf3 is doing something.
外观模式
外观模式为一个子系统提供一个简单的接口,以便于客户端使用。外观模式将复杂的子系统封装在一个简单的接口后面,使得客户端不需要知道子系统的具体实现。
适用场景:当一个系统有多个复杂的子系统,并且需要向客户端提供一个简单的接口时,可以使用外观模式。
首先,创建一个外观类,该类提供一个简单的接口,用于访问系统中的子系统:
public class Facade {
private Subsystem1 subsystem1;
private Subsystem2 subsystem2;
private Subsystem3 subsystem3;
public Facade() {
subsystem1 = new Subsystem1();
subsystem2 = new Subsystem2();
subsystem3 = new Subsystem3();
}
public void operation() {
subsystem1.operation1();
subsystem2.operation2();
subsystem3.operation3();
}
}
接下来,创建子系统类,这些类实现了系统中的各种功能:
public class Subsystem1 {
public void operation1() {
System.out.println("Subsystem1 operation");
}
}
public class Subsystem2 {
public void operation2() {
System.out.println("Subsystem2 operation");
}
}
public class Subsystem3 {
public void operation3() {
System.out.println("Subsystem3 operation");
}
}
最后,在客户端代码中,使用外观类来访问子系统中的功能:
public class Client {
public static void main(String[] args) {
Facade facade = new Facade();
facade.operation();
}
}
享元模式
定义:享元模式通过共享对象,以减少对象的创建和内存消耗。享元模式将一个大对象分解成多个小对象,并且共享这些小对象。
适用场景:当一个系统需要创建大量的相似对象时,可以使用享元模式。比如对于一个文本编辑器,需要创建大量的字母和符号,可以使用享元模式将这些字母和符号共享。
首先,创建一个享元接口,该接口定义了需要共享的方法:
public interface Flyweight {
void operation();
}
接下来,创建具体享元类,该类实现了享元接口,并包含了需要共享的状态:
public class ConcreteFlyweight implements Flyweight {
private String state;
public ConcreteFlyweight(String state) {
this.state = state;
}
public void operation() {
System.out.println("ConcreteFlyweight operation, state = " + state);
}
}
接着,创建享元工厂类,该类实现了享元对象的共享管理:
public class FlyweightFactory {
private Map<String, Flyweight> flyweights = new HashMap<>();
public Flyweight getFlyweight(String key) {
Flyweight flyweight = flyweights.get(key);
if (flyweight == null) {
flyweight = new ConcreteFlyweight(key);
flyweights.put(key, flyweight);
}
return flyweight;
}
}
最后,在客户端代码中使用享元工厂来获取共享对象:
public class Client {
public static void main(String[] args) {
FlyweightFactory factory = new FlyweightFactory();
Flyweight flyweight1 = factory.getFlyweight("key1");
flyweight1.operation();
Flyweight flyweight2 = factory.getFlyweight("key2");
flyweight2.operation();
Flyweight flyweight3 = factory.getFlyweight("key1");
flyweight3.operation();
System.out.println(flyweight1 == flyweight3); // 输出true,表明共享了同一个对象
}
}
在上述代码中,客户端代码通过享元工厂获取共享对象,如果对象已经存在则返回已经存在的对象,否则创建一个新的对象并返回。由于共享对象的存在,内存占用得到了优化。
行为型设计模式
策略模式
策略模式的作用是将一组算法或行为封装成一个类,使得它们之间可以相互替换,从而使得算法或行为的变化独立于使用它们的客户端。这样,客户端可以在运行时动态地选择所需要的算法或行为,而不需要修改客户端的代码,从而提高了代码的灵活性和可维护性。此外,策略模式还可以将不同的算法或行为进行归类、封装和复用,使得代码更加简洁、清晰、可读和可理解。
实现
首先,我们需要定义一个策略接口,它包含了所有算法所需的方法:
interface Strategy {
int execute(int a, int b);
}
然后,我们可以实现具体的算法:
class AddStrategy implements Strategy {
public int execute(int a, int b) {
return a + b;
}
}
class SubtractStrategy implements Strategy {
public int execute(int a, int b) {
return a - b;
}
}
class MultiplyStrategy implements Strategy {
public int execute(int a, int b) {
return a * b;
}
}
接下来,我们需要定义一个策略上下文,它包含了一个策略对象和一个执行方法:
class Context {
private Strategy strategy;
public Context(Strategy strategy) {
this.strategy = strategy;
}
public int executeStrategy(int a, int b) {
return strategy.execute(a, b);
}
}
最后,我们可以使用策略模式来执行我们的算法:
Context context = new Context(new AddStrategy());
System.out.println(context.executeStrategy(10,5)); // Output:15
context = new Context(new SubtractStrategy());
System.out.println(context.executeStrategy(10,5)); // Output:5
context = new Context(new MultiplyStrategy());
System.out.println(context.executeStrategy(10,5)); // Output:50
这里,我们通过创建不同的策略对象来实现不同的算法,并且在运行时选择算法。
观察者模式
定义了一种一对多的依赖关系,让多个观察者对象同时监听某一个主题对象。当主题对象状态发生改变时,所有依赖于它的观察者都会得到通知并自动更新。优点在于松耦合、易扩展,应用场景是需要多个对象对同一事件作出反应的场合。
● 定义主题接口Subject,包含注册观察者、移除观察者、通知所有观察者等方法。
public interface Subject {
void registerObserver(Observer observer);
void removeObserver(Observer observer);
void notifyObservers();
}
● 实现具体主题类ConcreteSubject,维护一个观察者列表和一个状态变量,实现主题接口的方法。当状态变化时,调用notifyObservers方法通知所有观察者。
public class ConcreteSubject implements Subject {
private List<Observer> observerList = new ArrayList<>();
private int state;
public void setState(int state) {
this.state = state;
notifyObservers();
}
@Override
public void registerObserver(Observer observer) {
observerList.add(observer);
}
@Override
public void removeObserver(Observer observer) {
observerList.remove(observer);
}
@Override
public void notifyObservers() {
for (Observer observer : observerList) {
observer.update(state);
}
}
}
- 定义观察者接口Observer,包含更新方法。
public interface Observer {
void update(int state);
}
- 实现具体观察者类ConcreteObserver,实现观察者接口的更新方法。
public class ConcreteObserver implements Observer {
private String name;
public ConcreteObserver(String name) {
this.name = name;
}
@Override
public void update(int state) {
System.out.println(name + " received state update: " + state);
}
}
- 在客户端代码中创建具体主题和观察者对象,将观察者注册到主题中,并通过修改主题状态来测试观察者模式的实现。
public class Client {
public static void main(String[] args) {
ConcreteSubject subject = new ConcreteSubject();
subject.registerObserver(new ConcreteObserver("Observer1"));
subject.registerObserver(new ConcreteObserver("Observer2"));
subject.setState(1);
subject.setState(2);
subject.setState(3);
}
}
命令模式
将请求封装成对象,以便在运行时更改其状态。应用场景包括:需要将请求和执行分离,或者是需要实现可撤销的操作。
首先,我们需要定义一个命令接口,该接口应该包含执行和撤销方法。
public interface Command {
void execute();
void undo();
}
接下来,我们需要实现具体的命令类。这些类将实现命令接口,并实现具体的操作。例如,我们可以创建一个开灯命令类和一个关灯命令类。
public class LightOnCommand implements Command {
private Light light;
public LightOnCommand(Light light) {
this.light = light;
}
public void execute() {
light.turnOn();
}
public void undo() {
light.turnOff();
}
}
public class LightOffCommand implements Command {
private Light light;
public LightOffCommand(Light light) {
this.light = light;
}
public void execute() {
light.turnOff();
}
public void undo() {
light.turnOn();
}
}
现在,我们需要实现调用者,它将接收命令并执行它。调用者可以是一个简单的遥控器。
public class RemoteControl {
private Command command;
public void setCommand(Command command) {
this.command = command;
}
public void buttonPressed() {
command.execute();
}
public void undoButtonPressed() {
command.undo();
}
}
现在,我们可以使用命令模式来控制灯的开关。首先,我们需要创建一个灯对象和一个遥控器对象。
Light light = new Light();
RemoteControl remoteControl = new RemoteControl();
然后,我们可以创建一个开灯命令和一个关灯命令,并将它们分别绑定到遥控器的按钮上。
Command lightOnCommand = new LightOnCommand(light);
remoteControl.setCommand(lightOnCommand);
Command lightOffCommand = new LightOffCommand(light);
remoteControl.setCommand(lightOffCommand);
现在,我们可以按下遥控器的按钮来控制灯的开关。
remoteControl.buttonPressed(); // Turn on the light
remoteControl.buttonPressed(); // Turn off the light
我们还可以撤销上一个命令。
remoteControl.undoButtonPressed(); // Undo the last command
模板方法模式
定义了一个算法的骨架,将具体的实现和步骤延迟到子类中实现。应用场景包括:需要在不同的子类中实现不同的算法细节,但基本的算法骨架是相同的。
实现
- 创建一个抽象类,其中包含一个具体方法和一些抽象方法。具体方法定义了算法的基本骨架,而抽象方法则是待子类实现的步骤。
- 创建一个具体子类,该子类继承自抽象类,并实现其中的所有抽象方法。
- 在具体子类中可以选择实现或覆盖基类中的具体方法。
- 创建一个客户端类,用于测试模板方法模式的效果。
abstract class AbstractClass {
// 模板方法
public final void templateMethod() {
primitiveOperation1();
primitiveOperation2();
concreteOperation();
hook();
}
// 抽象方法
protected abstract void primitiveOperation1();
// 抽象方法
protected abstract void primitiveOperation2();
// 具体方法
private void concreteOperation() {
System.out.println("执行具体方法");
}
// 钩子方法
protected void hook() {
System.out.println("执行钩子方法");
}
}
class ConcreteClass extends AbstractClass {
// 实现抽象方法
protected void primitiveOperation1() {
System.out.println("执行具体子类方法1");
}
// 实现抽象方法
protected void primitiveOperation2() {
System.out.println("执行具体子类方法2");
}
}
public class Client {
public static void main(String[] args) {
AbstractClass abstractClass = new ConcreteClass();
abstractClass.templateMethod();
}
}
迭代器模式
提供一种访问一个容器(集合)对象中各个元素的方式,而又不需要暴露该对象的内部表示。应用场景包括:需要遍历一个集合对象的元素,但是不希望暴露该对象的内部实现。
● 定义迭代器接口
public interface Iterator<T> {
boolean hasNext();
T next();
}
● 定义集合接口
public interface Collection<T> {
Iterator<T> iterator();
}
● 实现迭代器和集合接口
import java.util.ArrayList;
import java.util.List;
public class MyIterator<T> implements Iterator<T> {
private List<T> list;
private int index =0;
public MyIterator(List<T> list) {
this.list = list;
}
@Override
public boolean hasNext() {
return index < list.size();
}
@Override
public T next() {
if (hasNext()) {
return list.get(index++);
}
return null;
}
}
public class MyCollection<T> implements Collection<T> {
private List<T> list = new ArrayList<>();
@Override
public Iterator<T> iterator() {
return new MyIterator<>(list);
}
public void add(T t) {
list.add(t);
}
}
● 使用迭代器遍历集合
public class Client {
public static void main(String[] args) {
MyCollection<String> collection = new MyCollection<>();
collection.add("Java");
collection.add("Python");
collection.add("C++");
Iterator<String> iterator = collection.iterator();
while (iterator.hasNext()) {
System.out.println(iterator.next());
}
}
}
责任链模式
责任链模式是一种行为模式,它允许多个对象处理同一个请求,这些对象被组织成一条链,请求在链上依次被传递,直到有一个对象处理它为止。在责任链模式中,每个节点(处理器)都有自己的处理逻辑和指向下一个节点的指针。
应用场景包括:需要实现松耦合的对象间交互,或者是需要动态地改变请求的处理方式。
首先,我们需要定义一个处理器接口:
public interface Handler {
void setNextHandler(Handler nextHandler);
void handleRequest(Request request);
}
接着,我们可以定义一个抽象处理器类,实现Handler接口中的一些通用逻辑:
public abstract class AbstractHandler implements Handler {
private Handler nextHandler;
@Override
public void setNextHandler(Handler nextHandler) {
this.nextHandler = nextHandler;
}
@Override
public void handleRequest(Request request) {
if (nextHandler != null) {
nextHandler.handleRequest(request);
}
}
}
接下来,我们可以定义一些具体的处理器类,它们分别处理不同类型的请求:
public class ConcreteHandlerA extends AbstractHandler {
@Override
public void handleRequest(Request request) {
if (request.getType() == RequestType.TYPE_A) {
System.out.println("ConcreteHandlerA handles the request");
} else {
super.handleRequest(request);
}
}
}
public class ConcreteHandlerB extends AbstractHandler {
@Override
public void handleRequest(Request request) {
if (request.getType() == RequestType.TYPE_B) {
System.out.println("ConcreteHandlerB handles the request");
} else {
super.handleRequest(request);
}
}
}
public class ConcreteHandlerC extends AbstractHandler {
@Override
public void handleRequest(Request request) {
if (request.getType() == RequestType.TYPE_C) {
System.out.println("ConcreteHandlerC handles the request");
} else {
super.handleRequest(request);
}
}
}
最后,我们可以将这些处理器对象按照一定的顺序组成一条链:
Handler handlerA = new ConcreteHandlerA();
Handler handlerB = new ConcreteHandlerB();
Handler handlerC = new ConcreteHandlerC();
handlerA.setNextHandler(handlerB);
handlerB.setNextHandler(handlerC);
这样,当一个请求到来时,它会从链的头部开始传递,直到有一个处理器能够处理它为止:
Request request1 = new Request(RequestType.TYPE_A);
handlerA.handleRequest(request1); // output: ConcreteHandlerA handles the request
Request request2 = new Request(RequestType.TYPE_C);
handlerA.handleRequest(request2); // output: ConcreteHandlerC handles the request
Request request3 = new Request(RequestType.TYPE_D);
handlerA.handleRequest(request3); // output: Request cannot be handled
状态模式
状态模式是一种设计模式,用于管理对象的状态,并封装每个状态的行为。允许对象在其内部状态改变时改变其行为。应用场景包括:需要动态地改变对象的行为,或者是对象的行为取决于其内部状态。
- 定义一个状态接口,该接口包含状态对象的行为。
public interface State {
public void doAction(Context context);
}
- 实现状态接口,为每个状态定义具体的行为。
public class StateA implements State {
public void doAction(Context context) {
System.out.println("State A");
context.setState(this);
}
}
public class StateB implements State {
public void doAction(Context context) {
System.out.println("State B");
context.setState(this);
}
}
- 定义一个上下文类,该类包含状态对象并调用其行为。
public class Context {
private State state;
public Context(){
state = null;
}
public void setState(State state){
this.state = state;
}
public State getState(){
return state;
}
public void doAction(){
state.doAction(this);
}
}
- 在客户端代码中使用上下文对象和状态对象。
public class Client {
public static void main(String[] args) {
Context context = new Context();
State stateA = new StateA();
stateA.doAction(context);
State stateB = new StateB();
stateB.doAction(context);
}
}