Java 设计模式
设计模式是被普遍接受的、经过验证的最佳实践,用于解决特定情况下的常见问题。Java 设计模式是在 Java 程序设计中使用的设计模式。
创建型模式
创建型模式关注如何实例化一个对象,可以根据实例化的方式分为以下几类:
工厂模式
工厂模式是一种创建型模式,用于创建对象而无需指定将要创建的对象的确切类。它提供了一种将代码从实际创建对象的过程中解耦的方式。工厂模式包括:
- 简单工厂模式
当您需要根据给定的参数创建某个对象时,可以使用简单工厂模式。下面是一个简单工厂模式的Java代码示例:
public interface Shape {
void draw();
}
public class Circle implements Shape {
@Override
public void draw() {
System.out.println("Drawing a circle.");
}
}
public class Rectangle implements Shape {
@Override
public void draw() {
System.out.println("Drawing a rectangle.");
}
}
public class ShapeFactory {
public static Shape createShape(String shapeType) {
if (shapeType.equalsIgnoreCase("circle")) {
return new Circle();
} else if (shapeType.equalsIgnoreCase("rectangle")) {
return new Rectangle();
} else {
throw new IllegalArgumentException("Invalid shape type: " + shapeType);
}
}
}
public class Client {
public static void main(String[] args) {
Shape circle = ShapeFactory.createShape("circle");
circle.draw(); // 输出 "Drawing a circle."
Shape rectangle = ShapeFactory.createShape("rectangle");
rectangle.draw(); // 输出 "Drawing a rectangle."
}
}
在上面的示例中,ShapeFactory
是一个简单工厂类,它根据传入的参数来创建一个 Shape
对象。在客户端中,我们可以通过调用 ShapeFactory.createShape()
方法来创建具体的 Shape
对象,而不需要直接调用 Circle
或 Rectangle
的构造函数。这样,我们可以将对象的创建逻辑封装在工厂类中,从而实现更好的代码复用性和可维护性。
- 工厂方法模式
工厂方法模式是一种创建型设计模式,它定义了一个用于创建对象的接口,但是让子类决定实例化哪一个类。下面是一个工厂方法模式的Java代码示例:
public interface Animal {
void say();
}
public class Cat implements Animal {
@Override
public void say() {
System.out.println("I am a cat.");
}
}
public class Dog implements Animal {
@Override
public void say() {
System.out.println("I am a dog.");
}
}
public interface AnimalFactory {
Animal createAnimal();
}
public class CatFactory implements AnimalFactory {
@Override
public Animal createAnimal() {
return new Cat();
}
}
public class DogFactory implements AnimalFactory {
@Override
public Animal createAnimal() {
return new Dog();
}
}
public class Client {
public static void main(String[] args) {
AnimalFactory factory = new CatFactory();
Animal animal = factory.createAnimal();
animal.say(); // 输出 "I am a cat."
}
}
在上面的示例中,我们定义了一个 Animal
接口和两个实现类 Cat
和 Dog
。接着,我们定义了一个 AnimalFactory
接口和两个实现类 CatFactory
和 DogFactory
,它们分别创建 Cat
和 Dog
对象。在客户端中,我们可以通过调用 AnimalFactory.createAnimal()
方法来创建具体的 Animal
对象,而不需要直接调用 Cat
或 Dog
的构造函数。这样,我们可以将对象的创建逻辑封装在工厂类中,从而实现更好的代码复用性和可维护性。
- 抽象工厂模式
抽象工厂模式是一种创建型设计模式,它提供了一种方式,可以在不指定具体类的情况下创建一系列相关或依赖对象的家族。下面是一个抽象工厂模式的Java代码示例:
public interface Animal {
void say();
}
public class Cat implements Animal {
@Override
public void say() {
System.out.println("I am a cat.");
}
}
public class Dog implements Animal {
@Override
public void say() {
System.out.println("I am a dog.");
}
}
public interface Food {
void eat();
}
public class Fish implements Food {
@Override
public void eat() {
System.out.println("I am eating fish.");
}
}
public class Bone implements Food {
@Override
public void eat() {
System.out.println("I am eating bone.");
}
}
public interface AnimalFactory {
Animal createAnimal();
Food createFood();
}
public class CatFactory implements AnimalFactory {
@Override
public Animal createAnimal() {
return new Cat();
}
@Override
public Food createFood() {
return new Fish();
}
}
public class DogFactory implements AnimalFactory {
@Override
public Animal createAnimal() {
return new Dog();
}
@Override
public Food createFood() {
return new Bone();
}
}
public class Client {
public static void main(String[] args) {
AnimalFactory factory = new CatFactory();
Animal animal = factory.createAnimal();
Food food = factory.createFood();
animal.say(); // 输出 "I am a cat."
food.eat(); // 输出 "I am eating fish."
}
}
在上面的示例中,我们定义了两个产品族:Animal
和 Food
。每个产品族都有两个具体产品:Cat
和 Dog
,以及 Fish
和 Bone
。为了创建这些产品,我们定义了一个 AnimalFactory
接口,它有两个方法分别用于创建 Animal
和 Food
对象。接着,我们实现了两个具体的工厂类 CatFactory
和 DogFactory
,它们分别创建 Cat
和 Dog
,以及 Fish
和 Bone
对象。在客户端中,我们可以通过调用 AnimalFactory.createAnimal()
和 AnimalFactory.createFood()
方法来创建具体的 Animal
和 Food
对象,而不需要直接调用 Cat
、Dog
、Fish
或 Bone
的构造函数。这样,我们可以将对象的创建逻辑封装在工厂类中,从而实现更好的代码复用性和可维护性。
单例模式
单例模式是一种创建型模式,确保一个类只有一个实例,并提供全局访问点。它通常是通过在类中创建一个私有构造函数、一个私有静态变量和一个公共静态方法来实现的。
单例模式有以下几种实现方式:
- 懒汉式单例模式:在第一次使用时才创建单例对象,线程不安全。
public class Singleton {
private static Singleton instance;
private Singleton() {
// 构造函数私有化,防止外部直接实例化该类
}
public static Singleton getInstance() {
if (instance == null) {
instance = new Singleton();
}
return instance;
}
}
- 懒汉式单例模式(线程安全):在第一次使用时才创建单例对象,使用同步锁保证线程安全,但性能较差。
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 static Singleton instance = new Singleton();
private Singleton() {
// 构造函数私有化,防止外部直接实例化该类
}
public static Singleton getInstance() {
return instance;
}
}
- 双重检查锁单例模式:使用双重检查锁保证线程安全,同时延迟加载,性能较好。
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;
}
}
- 静态内部类单例模式:使用静态内部类来实现懒加载和线程安全,同时也保证了单例的唯一性。
public class Singleton {
private Singleton() {
// 构造函数私有化,防止外部直接实例化该类
}
private static class SingletonHolder {
private static final Singleton INSTANCE = new Singleton();
}
public static Singleton getInstance() {
return SingletonHolder.INSTANCE;
}
}
以上是几种常见的单例模式实现方式,每种实现方式都有其优缺点,开发者可以根据自己的需求选择合适的实现方式。
建造者模式
建造者模式是一种创建型模式,它允许您通过使用简单的对象逐步构建复杂的对象。它通过将构造过程拆分成一系列简单的步骤来完成。
建造者模式是一种创建型设计模式,它可以将一个复杂对象的构建过程与其表示分离,使得同样的构建过程可以创建不同的表示。常见的建造者模式实现方式有以下几种:
- 普通建造者模式:在建造者模式中,我们通常会定义一个抽象建造者接口,以及一个具体的建造者类来实现该接口。对于不同的产品,我们可以定义不同的具体建造者类来实现建造过程,并在最终的产品中返回由该建造者创建的对象。
public interface Builder {
void buildPart1();
void buildPart2();
Product getResult();
}
public class ConcreteBuilder implements Builder {
private Product product = new Product();
public void buildPart1() {
product.setPart1("Part1");
}
public void buildPart2() {
product.setPart2("Part2");
}
public Product getResult() {
return product;
}
}
public class Product {
private String part1;
private String part2;
public void setPart1(String part1) {
this.part1 = part1;
}
public void setPart2(String part2) {
this.part2 = part2;
}
public String getPart1() {
return part1;
}
public String getPart2() {
return part2;
}
}
public class Director {
private Builder builder;
public Director(Builder builder) {
this.builder = builder;
}
public void construct() {
builder.buildPart1();
builder.buildPart2();
}
}
public class Client {
public static void main(String[] args) {
Builder builder = new ConcreteBuilder();
Director director = new Director(builder);
director.construct();
Product product = builder.getResult();
System.out.println(product.getPart1() + ", " + product.getPart2());
}
}
在上面的示例中,我们定义了一个 Builder
接口,其中包括了构建产品所需的方法。我们还定义了一个具体的建造者类 ConcreteBuilder
,该类实现了 Builder
接口中的方法,用于构建产品。我们还定义了一个产品类 Product
,其中包括了产品的属性和方法。在 Director
类中,我们使用 Builder
接口来构建产品,并通过调用 getResult()
方法来获取最终的产品对象。在客户端中,我们创建了一个具体的建造者对象,并将其传递给 Director
对象,然后调用 construct()
方法来构建产品,并通过调用 getResult()
方法来获取最终的产品对象。
- 链式调用建造者模式:链式调用建造者模式可以使得代码更加简洁,同时也可以避免一些重复的代码。
public class Product {
private String part1;
private String part2;
public Product setPart1(String part1) {
this.part1 = part1;
return this;
}
public Product setPart2(String part2) {
this.part2 = part2;
return this;
}
public String getPart1() {
return part1;
}
public String getPart2() {
return part2;
}
}
public class Director {
public Product construct() {
return new Product()
.setPart1("Part1")
.setPart2("Part2");
}
}
public class Client {
public static void main(String[] args) {
Director director = new Director();
Product product = director.construct();
System.out.println(product.getPart1() + ", " + product.getPart2());
}
}
在上面的示例中,我们定义了一个 Product
类,其中包括了产品的属性和方法,并将其设置为可链式调用。在 Director
类中,我们直接使用链式调用来构建产品,并返回最终的产品对象。在客户端中,我们创建了一个 Director
对象,并调用其 construct()
方法来构建产品,并通过调用 getPart1()
和 getPart2()
方法来获取产品的属性。
以上是建造者模式的两种常见实现方式,每种实现方式都都有其优缺点,选择哪种实现方式取决于具体的应用场景和需求。
普通建造者模式的优点是结构清晰,建造过程可控,适用于构建较为复杂的对象;缺点是代码量较大,建造者类的个数会随着产品的复杂度而增加,不利于维护和扩展。
链式调用建造者模式的优点是代码简洁,易于阅读和理解,适用于构建简单的对象;缺点是不够灵活,无法控制建造过程,不适用于构建较为复杂的对象。
除了以上两种实现方式,还有一些其他的建造者模式实现方式,例如使用反射机制来构建对象,使用 XML 或 JSON 配置文件来配置对象的属性等。在选择建造者模式的实现方式时,需要根据具体的应用场景和需求进行选择,以达到最佳的效果。
原型模式
原型模式是一种创建型模式,它允许您通过复制现有对象来创建新对象,而不是通过实例化新对象来创建。
原型模式是一种创建型设计模式,它可以通过复制现有的对象来创建新的对象,从而避免了使用类的构造函数进行创建的过程。常见的原型模式实现方式有以下几种:
- 浅克隆:浅克隆是最基本的原型模式实现方式,它只会复制对象的基本数据类型和引用类型的地址,而不会复制引用类型所指向的对象。通过实现
Cloneable
接口和重写clone()
方法来实现浅克隆。
public class Prototype implements Cloneable {
private int number;
private List<String> list;
public Prototype(int number, List<String> list) {
this.number = number;
this.list = list;
}
@Override
public Prototype clone() throws CloneNotSupportedException {
return (Prototype) super.clone();
}
public int getNumber() {
return number;
}
public List<String> getList() {
return list;
}
}
public class Client {
public static void main(String[] args) throws CloneNotSupportedException {
Prototype prototype = new Prototype(1, new ArrayList<>());
prototype.getList().add("A");
Prototype clone = prototype.clone();
clone.getList().add("B");
System.out.println(prototype.getList()); // [A, B]
System.out.println(clone.getList()); // [A, B]
}
}
在上面的示例中,我们定义了一个 Prototype
类,其中包括了一个基本数据类型和一个引用类型的属性。在 Prototype
类中,我们实现了 Cloneable
接口,并重写了 clone()
方法来实现浅克隆。在客户端中,我们创建了一个 Prototype
对象,并向其引用类型的属性中添加了一个元素,然后通过调用 clone()
方法来创建一个克隆对象,最后向克隆对象的引用类型的属性中添加了一个元素。由于浅克隆只会复制引用类型的地址,所以克隆对象和原对象的引用类型属性指向的是同一个对象,因此它们的引用类型属性中都包含了两个元素。
- 深克隆:深克隆会复制对象的所有属性,包括引用类型所指向的对象。为了实现深克隆,我们可以使用序列化和反序列化的方式来创建新的对象。
public class Prototype implements Serializable {
private int number;
private List<String> list;
public Prototype(int number, List<String> list) {
this.number = number;
this.list = list;
}
public Prototype clone() throws IOException, ClassNotFoundException {
ByteArrayOutputStream bos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(bos);
oos.writeObject(this);
ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray());
ObjectInputStream ois = new ObjectInputStream(bis);
return (Prototype) ois.readObject();
}
public int getNumber() {
return number;
}
public List<String> getList() {
return list;
}
}
public class Client {
public static void main(String[] args) throws IOException, ClassNotFoundException {
Prototype prototype = new Prototype(1, new ArrayList<>());
prototype.getList().add("A");
Prototype clone = prototype.clone();
clone.getList().add("B");
System.out.println(prototype.getList()); // [A]
System.out.println(clone.getList()); // [A, B]
}
}
在上面的示例中,我们同样定义了一个 Prototype
类,并实现了 Serializable
接口来实现深克隆。在 Prototype
类中,我们定义了一个 clone()
方法,该方法将对象序列化为字节数组,并将其反序列化为新的对象。在客户端中,我们创建了一个 Prototype
对象,并向其引用类型的属性中添加了一个元素,然后通过调用 clone()
方法来创建一个深克隆的对象,最后向克隆对象的引用类型的属性中添加了一个元素。由于深克隆会复制对象的所有属性,所以克隆对象和原对象的引用类型属性指向的是不同的对象,因此它们的引用类型属性中包含的元素也不同。
- 原型管理器:原型管理器是一种更高级的原型模式实现方式,它将原型对象保存在一个集合中,客户端可以通过指定原型对象的名称来获取该对象的克隆对象。
public class Prototype implements Cloneable {
private String name;
public Prototype(String name) {
this.name = name;
}
@Override
public Prototype clone() throws CloneNotSupportedException {
return (Prototype) super.clone();
}
public String getName() {
return name;
}
}
public class PrototypeManager {
private Map<String, Prototype> map = new HashMap<>();
public PrototypeManager() {
map.put("prototype1", new Prototype("prototype1"));
map.put("prototype2", new Prototype("prototype2"));
}
public void addPrototype(String name, Prototype prototype) {
map.put(name, prototype);
}
public Prototype getPrototype(String name) throws CloneNotSupportedException {
return map.get(name).clone();
}
}
public class Client {
public static void main(String[] args) throws CloneNotSupportedException {
PrototypeManager manager = new PrototypeManager();
Prototype prototype1 = manager.getPrototype("prototype1");
Prototype prototype2 = manager.getPrototype("prototype2");
Prototype prototype3 = new Prototype("prototype3");
manager.addPrototype("prototype3", prototype3);
Prototype prototype4 = manager.getPrototype("prototype3");
System.out.println(prototype1.getName()); // prototype1
System.out.println(prototype2.getName()); // prototype2
System.out.println(prototype3.getName()); // prototype3
System.out.println(prototype4.getName()); // prototype3
}
}
在上面的示例中,我们定义了一个 Prototype
类,并实现了 Cloneable
接口,以支持克隆操作。然后我们定义了一个 PrototypeManager
类,该类将原型对象保存在一个集合中,并提供了添加原型对象和获取原型对象的方法。在客户端中,我们通过获取 PrototypeManager
的实例来获取原型对象的克隆对象,并可以通过添加原型对象来扩展原型管理器的功能。
- 序列化和反序列化:在 Java 中,可以通过序列化和反序列化来实现原型模式。序列化是将对象转换为字节流的过程,而反序列化则是将字节流转换回对象的过程。通过序列化和反序列化,可以在不改变原型对象的情况下,生成该对象的一个深层副本。
import java.io.*;
public class Prototype implements Serializable {
private String name;
private SerializableObject obj;
public Prototype(String name, SerializableObject obj) {
this.name = name;
this.obj = obj;
}
public Prototype deepClone() throws IOException, ClassNotFoundException {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(baos);
oos.writeObject(this);
ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
ObjectInputStream ois = new ObjectInputStream(bais);
return (Prototype) ois.readObject();
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public SerializableObject getObj() {
return obj;
}
public void setObj(SerializableObject obj) {
this.obj = obj;
}
}
public class SerializableObject implements Serializable {
private static final long serialVersionUID = 1L;
}
public class Client {
public static void main(String[] args) throws IOException, ClassNotFoundException {
SerializableObject obj = new SerializableObject();
Prototype prototype1 = new Prototype("prototype1", obj);
Prototype prototype2 = prototype1.deepClone();
System.out.println(prototype1 == prototype2); // false
System.out.println(prototype1.getObj() == prototype2.getObj()); // false
}
}
在上面的示例中,我们定义了一个 Prototype
类,并实现了 Serializable
接口,以支持序列化和反序列化操作。在 Prototype
类中,我们定义了一个 deepClone()
方法,该方法会将对象序列化成字节流,然后再反序列化回对象,生成一个深层副本。在客户端中,我们创建了一个原型对象 prototype1
,并通过 deepClone()
方法生成了一个深层副本 prototype2
。通过比较对象和对象中的引用类型属性,我们可以发现它们并不相等,说明 deepClone()
方法生成了一个深层副本。
总之,原型模式是一种创建型设计模式,它通过复制现有对象来创建新对象。原型模式可以分为浅克隆和深克隆两种,可以通过克隆方法、拷贝构造方法、原型管理器和序列化和反序列化等方式来实现。在实际开发中,原型模式可以用于创建复杂对象、减少对象创建时间和内存消耗、避免构造函数的复杂性和提高系统性能。
结构型模式
结构型模式关注类和对象如何组合形成更大的结构。可以根据组合方式分为以下几类:
适配器模式
适配器模式是一种结构型模式,用于将一个类的接口转换为另一个类的接口。它允许不兼容的类之间进行合作。
适配器模式是一种结构型设计模式,它用于将一个类的接口转换成客户端所期望的另一种接口。它可以将原本不兼容的接口转换为兼容的接口,从而使得原本无法一起工作的类能够协同工作。适配器模式有以下几种实现方式:
- 类适配器:类适配器使用继承来实现适配器功能,它继承一个现有的类,并实现一个新的接口来与原有类所提供的接口进行适配。由于 Java 不支持多重继承,因此类适配器只能适配一个类。
public interface Target {
void request();
}
public class Adaptee {
public void specificRequest() {
System.out.println("Adaptee specificRequest");
}
}
public class ClassAdapter extends Adaptee implements Target {
@Override
public void request() {
specificRequest();
}
}
public class Client {
public static void main(String[] args) {
Target target = new ClassAdapter();
target.request();
}
}
在上面的示例中,我们定义了一个 Target
接口和一个 Adaptee
类。然后我们定义了一个类适配器 ClassAdapter
,它继承了 Adaptee
类,并实现了 Target
接口,其中 request()
方法调用了 specificRequest()
方法。在客户端中,我们创建了一个 ClassAdapter
对象,并调用 request()
方法,它会调用 specificRequest()
方法,从而完成适配器的功能。
- 对象适配器:对象适配器使用组合来实现适配器功能,它包含一个原有类的对象,并实现一个新的接口来与原有类所提供的接口进行适配。由于 Java 支持组合,因此对象适配器可以适配多个类。
public interface Target {
void request();
}
public class Adaptee {
public void specificRequest() {
System.out.println("Adaptee specificRequest");
}
}
public class ObjectAdapter implements Target {
private Adaptee adaptee;
public ObjectAdapter(Adaptee adaptee) {
this.adaptee = adaptee;
}
@Override
public void request() {
adaptee.specificRequest();
}
}
public class Client {
public static void main(String[] args) {
Adaptee adaptee = new Adaptee();
Target target = new ObjectAdapter(adaptee);
target.request();
}
}
在上面的示例中,我们定义了一个对象适配器 ObjectAdapter
,它包含一个 Adaptee
对象,并实现了 Target
接口,其中 request()
方法调用了 adaptee
对象的 specificRequest()
方法。在客户端中,我们创建了一个 Adaptee
对象和一个 ObjectAdapter
对象,并调用 request()
方法,它会调用 specificRequest()
方法,从而完成适配器的功能。
- 接口适配器:接口适配器也称为缺省适配器,它通过提供一个抽象类来实现适配器功能,该抽象类实现了一个或多个接口,但是接口中的方法都是空的,这样就可以让子类只需要覆盖它们所需要的方法即可。接口适配器可以用于接口中方法的数量很多,但是客户端只需要调用其中几个方法的情况。
public interface Target {
void request();
void anotherRequest();
void thirdRequest();
}
public abstract class Adapter implements Target {
@Override
public void request() {}
@Override
public void anotherRequest() {}
@Override
public void thirdRequest() {}
}
public class Client {
public static void main(String[] args) {
Target target = new Adapter() {
@Override
public void request() {
System.out.println("Adapter request");
}
};
target.request();
}
}
在上面的示例中,我们定义了一个接口适配器 Adapter
,它实现了 Target
接口,但是接口中的方法都是空的。在客户端中,我们创建了一个匿名子类对象,并覆盖了 request()
方法,从而完成适配器的功能。
以上是适配器模式的三种常见实现方式,每种实现方式都有其优缺点,具体使用时需要根据实际情况进行选择。
桥接模式
桥接模式是一种结构型模式,用于将抽象部分与它们的实现部分分离,从而使它们可以独立变化。
在桥接模式中,抽象部分和实现部分都可以有自己的类层次结构,它们通过一个桥接接口连接起来。
桥接模式的实现方式有以下几种:
-
接口实现方式:抽象部分和实现部分都定义一个接口,然后在抽象类中持有一个实现接口的引用,通过这个引用调用实现部分的方法。
-
抽象类实现方式:抽象部分和实现部分都定义一个抽象类,然后在抽象类中持有一个实现抽象类的引用,通过这个引用调用实现部分的方法。
-
继承实现方式:在抽象类中定义抽象方法,然后在具体子类中实现这些抽象方法,从而实现抽象部分和实现部分的分离。
-
注入实现方式:将实现部分的对象通过构造函数或者属性注入到抽象部分中,然后在抽象部分中调用实现部分的方法。
总之,桥接模式的实现方式是多种多样的,具体的实现方式需要根据具体的场景来选择。
- 接口实现方式示例:
抽象部分接口:
public interface Shape {
void draw();
}
实现部分接口:
public interface Color {
void fill();
}
抽象类:
public abstract class AbstractShape {
protected Color color;
public AbstractShape(Color color) {
this.color = color;
}
public abstract void draw();
}
具体类:
public class Circle extends AbstractShape {
public Circle(Color color) {
super(color);
}
@Override
public void draw() {
System.out.print("画一个圆形,");
color.fill();
}
}
- 抽象类实现方式示例:
抽象类:
public abstract class AbstractShape {
protected Color color;
public AbstractShape(Color color) {
this.color = color;
}
public abstract void draw();
}
实现部分抽象类:
public abstract class AbstractColor {
public abstract void fill();
}
具体实现类:
public class RedColor extends AbstractColor {
@Override
public void fill() {
System.out.println("使用红色填充");
}
}
- 继承实现方式示例:
抽象类:
public abstract class AbstractShape {
public abstract void draw();
}
具体实现类:
public class Circle extends AbstractShape {
private Color color;
public Circle(Color color) {
this.color = color;
}
@Override
public void draw() {
System.out.print("画一个圆形,");
color.fill();
}
}
- 注入实现方式示例:
抽象类:
public abstract class AbstractShape {
protected Color color;
public void setColor(Color color) {
this.color = color;
}
public abstract void draw();
}
具体类:
public class Circle extends AbstractShape {
@Override
public void draw() {
System.out.print("画一个圆形,");
color.fill();
}
}
以上是桥接模式的几种实现方式,具体的实现方式可以根据不同的场景进行选择。
组合模式
组合模式是一种结构型模式,用于将对象组合成树形结构以表示部分-整体层次结构。它允许客户端统一处理单个对象和对象组合。
组合模式是一种结构型设计模式,其目的是将对象组合成树形结构以表示“部分-整体”的层次结构,使得用户对单个对象和组合对象的使用具有一致性。在组合模式中,树形结构中的节点可以是叶子节点,也可以是容器节点,容器节点可以包含叶子节点和其他容器节点。
组合模式的实现方式有以下两种:
-
透明方式:在组合模式中,将叶子节点和容器节点都看作是一个节点,它们实现相同的接口或抽象类,从而使得客户端可以统一处理。
-
安全方式:在组合模式中,将叶子节点和容器节点分开处理,容器节点包含一个或多个叶子节点和其他容器节点,从而使得客户端需要对容器节点和叶子节点分别进行处理。
以下是两种实现方式的示例:
- 透明方式示例:
抽象组件类:
public abstract class Component {
protected String name;
public Component(String name) {
this.name = name;
}
public abstract void add(Component component);
public abstract void remove(Component component);
public abstract void display(int depth);
}
叶子节点类:
public class Leaf extends Component {
public Leaf(String name) {
super(name);
}
@Override
public void add(Component component) {
System.out.println("不能添加叶子节点");
}
@Override
public void remove(Component component) {
System.out.println("不能删除叶子节点");
}
@Override
public void display(int depth) {
System.out.println("-".repeat(depth) + name);
}
}
容器节点类:
public class Composite extends Component {
private List<Component> children = new ArrayList<>();
public Composite(String name) {
super(name);
}
@Override
public void add(Component component) {
children.add(component);
}
@Override
public void remove(Component component) {
children.remove(component);
}
@Override
public void display(int depth) {
System.out.println("-".repeat(depth) + name);
for (Component child : children) {
child.display(depth + 2);
}
}
}
- 安全方式示例:
抽象组件类:
public abstract class Component {
protected String name;
public Component(String name) {
this.name = name;
}
public abstract void display(int depth);
}
叶子节点类:
public class Leaf extends Component {
public Leaf(String name) {
super(name);
}
@Override
public void display(int depth) {
System.out.println("-".repeat(depth) + name);
}
}
容器节点类:
public class Composite extends Component {
private List<Component> children = new ArrayList<>();
public Composite(String name) {
super(name);
}
public void add(Component component) {
children.add(component);
}
public void remove(Component component) {
children.remove(component);
}
@Override
public void display(int depth) {
System.out.println("-".repeat(depth) + name);
for (Component child : children) {
child.display(depth + 2);
}
}
}
以上是组合模式的两种实现方式,具体的实现方式可以根据不同的场景进行选择。
装饰器模式
装饰器模式是一种结构型模式,用于动态地将对象添加到现有对象中,从而扩展现有对象的功能。
装饰器模式是一种结构型设计模式,其目的是在不修改已有对象的情况下,动态地扩展其功能。装饰器模式通过在不改变原有对象接口的情况下,为对象增加新的行为,从而实现了对对象的透明性。
装饰器模式的实现方式有以下两种:
-
继承方式:通过继承被装饰对象的类,并重写其中的方法,来实现装饰器的功能。
-
组合方式:通过将被装饰对象作为成员变量,并在其中增加新的方法,来实现装饰器的功能。
以下是两种实现方式的示例:
- 继承方式示例:
抽象组件类:
public abstract class Component {
public abstract void operation();
}
具体组件类:
public class ConcreteComponent extends Component {
@Override
public void operation() {
System.out.println("执行具体组件的操作");
}
}
抽象装饰器类:
public abstract class Decorator extends Component {
protected Component component;
public Decorator(Component component) {
this.component = component;
}
@Override
public void operation() {
component.operation();
}
}
具体装饰器类:
public class ConcreteDecoratorA extends Decorator {
public ConcreteDecoratorA(Component component) {
super(component);
}
@Override
public void operation() {
super.operation();
System.out.println("为组件A增加的操作");
}
}
- 组合方式示例:
抽象组件类:
public abstract class Component {
public abstract void operation();
}
具体组件类:
public class ConcreteComponent extends Component {
@Override
public void operation() {
System.out.println("执行具体组件的操作");
}
}
抽象装饰器类:
public abstract class Decorator extends Component {
protected Component component;
public void setComponent(Component component) {
this.component = component;
}
@Override
public void operation() {
if (component != null) {
component.operation();
}
}
}
具体装饰器类:
public class ConcreteDecoratorA extends Decorator {
public void addBehavior() {
System.out.println("为组件A增加的操作");
}
}
以上是装饰器模式的两种实现方式,具体的实现方式可以根据不同的场景进行选择。
外观模式
外观模式是一种结构型模式,它为复杂的子系统提供了一个简单的接口,从而使其更易于使用。
外观模式是一种结构型设计模式,其目的是为复杂的子系统提供一个简单的接口,从而使得客户端可以更加方便地使用该子系统。外观模式将子系统的复杂性隐藏在一个外观类中,客户端只需要与该外观类交互即可,无需直接与子系统中的类交互。
外观模式的实现方式很简单,只需要定义一个外观类,该类封装了子系统中的多个类,客户端只需要与该外观类交互即可。外观类可以使用单例模式,以确保整个系统中只有一个外观类的实例。
以下是外观模式的示例:
外观类:
public class Facade {
private SubsystemA subsystemA;
private SubsystemB subsystemB;
private SubsystemC subsystemC;
public Facade() {
subsystemA = new SubsystemA();
subsystemB = new SubsystemB();
subsystemC = new SubsystemC();
}
public void operation() {
subsystemA.operationA();
subsystemB.operationB();
subsystemC.operationC();
}
}
子系统A:
public class SubsystemA {
public void operationA() {
System.out.println("SubsystemA operationA");
}
}
子系统B:
public class SubsystemB {
public void operationB() {
System.out.println("SubsystemB operationB");
}
}
子系统C:
public class SubsystemC {
public void operationC() {
System.out.println("SubsystemC operationC");
}
}
客户端:
public class Client {
public static void main(String[] args) {
Facade facade = new Facade();
facade.operation();
}
}
以上是外观模式的实现方式,通过外观类的封装,客户端可以更加方便地使用子系统中的功能。同时,如果子系统发生变化,只需要修改外观类即可,客户端无需修改原有的代码。
享元模式
享元模式是一种结构型模式,用于尽可能减少内存使用和对象数量,通过共享对象来实现这一点。
享元模式是一种结构型设计模式,其目的是通过共享对象来减少内存的使用,从而提高系统的性能。享元模式将对象分为内部状态和外部状态,内部状态是可以共享的,而外部状态是不可共享的。
享元模式的实现方式有以下两种:
-
池化方式:通过维护一个对象池,将已经创建的对象保存在池中,每次需要使用时,从池中获取对象,如果池中没有该对象,则创建一个新的对象。
-
共享方式:通过使用单例模式,将共享对象实例化为一个单例对象,多个客户端共享该对象。
以下是两种实现方式的示例:
- 池化方式示例:
抽象享元类:
public abstract class Flyweight {
public abstract void operation(UnsharedConcreteFlyweight state);
}
具体享元类:
public class ConcreteFlyweight extends Flyweight {
private String intrinsicState;
public ConcreteFlyweight(String intrinsicState) {
this.intrinsicState = intrinsicState;
}
@Override
public void operation(UnsharedConcreteFlyweight state) {
System.out.println("ConcreteFlyweight: intrinsicState=" + intrinsicState + ", extrinsicState=" + state.getExtrinsicState());
}
}
非共享具体享元类:
public class UnsharedConcreteFlyweight {
private String extrinsicState;
public UnsharedConcreteFlyweight(String extrinsicState) {
this.extrinsicState = extrinsicState;
}
public String getExtrinsicState() {
return extrinsicState;
}
public void setExtrinsicState(String extrinsicState) {
this.extrinsicState = extrinsicState;
}
}
享元工厂类:
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("a");
Flyweight flyweight2 = factory.getFlyweight("a");
UnsharedConcreteFlyweight unsharedConcreteFlyweight = new UnsharedConcreteFlyweight("b");
flyweight1.operation(unsharedConcreteFlyweight);
flyweight2.operation(unsharedConcreteFlyweight);
}
}
- 共享方式示例:
抽象享元类:
public abstract class Flyweight {
public abstract void operation();
}
具体享元类:
public class ConcreteFlyweight extends Flyweight {
private static ConcreteFlyweight instance = new ConcreteFlyweight();
private ConcreteFlyweight() {}
public static ConcreteFlyweight getInstance() {
return instance;
}
@Override
public void operation() {
System.out.println("ConcreteFlyweight operation");
}
}
客户端:
public class Client {
public static void main(String[] args) {
Flyweight flyweight1 = ConcreteFlyweight.getInstance();
Flyweight flyweight2 = ConcreteFlyweight.getInstance();
flyweight1.operation();
flyweight2.operation();
}
}
以上是享元模式的两种实现方式的示例。通过共享对象,可以减少内存的使用,提高系统的性能。同时,享元模式还可以减少对象的创建,降低系统的复杂度。
代理模式
代理模式是一种结构型模式,用于为其他对象提供一个代理以控制对这个对象的访问。
代理模式是一种结构型设计模式,其目的是为其他对象提供一种代理以控制对这个对象的访问。代理模式通常是在客户端和实际对象之间引入一个代理对象,客户端通过代理对象来访问实际对象,从而实现对实际对象的控制。
代理模式的实现方式有以下几种:
-
静态代理:代理类在编译期间就已经确定,代理类和目标类实现相同的接口或继承相同的类。
-
动态代理:代理类在运行期间动态生成,代理类实现相同的接口或继承相同的类。
-
CGLIB代理:基于继承的代理方式,通过生成目标类的子类来实现代理。
以下是三种实现方式的示例:
- 静态代理示例:
接口:
public interface Subject {
void request();
}
目标类:
public class RealSubject implements Subject {
@Override
public void request() {
System.out.println("RealSubject request");
}
}
代理类:
public class Proxy implements Subject {
private RealSubject realSubject;
public Proxy(RealSubject realSubject) {
this.realSubject = realSubject;
}
@Override
public void request() {
System.out.println("Proxy request");
realSubject.request();
}
}
客户端:
public class Client {
public static void main(String[] args) {
RealSubject realSubject = new RealSubject();
Proxy proxy = new Proxy(realSubject);
proxy.request();
}
}
- 动态代理示例:
接口:
public interface Subject {
void request();
}
目标类:
public class RealSubject implements Subject {
@Override
public void request() {
System.out.println("RealSubject request");
}
}
代理类:
public class DynamicProxy implements InvocationHandler {
private Object target;
public DynamicProxy(Object target) {
this.target = target;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("DynamicProxy before");
Object result = method.invoke(target, args);
System.out.println("DynamicProxy after");
return result;
}
}
客户端:
public class Client {
public static void main(String[] args) {
RealSubject realSubject = new RealSubject();
DynamicProxy dynamicProxy = new DynamicProxy(realSubject);
Subject proxy = (Subject) Proxy.newProxyInstance(realSubject.getClass().getClassLoader(), realSubject.getClass().getInterfaces(), dynamicProxy);
proxy.request();
}
}
- CGLIB代理示例:
目标类:
public class RealSubject {
public void request() {
System.out.println("RealSubject request");
}
}
代理类:
public class CglibProxy implements MethodInterceptor {
private Object target;
public CglibProxy(Object target) {
this.target = target;
}
public Object getProxy() {
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(target.getClass());
enhancer.setCallback(this);
return enhancer.create();
}
@Override
public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
System.out.println("CglibProxy before");
Object result = method.invoke(target, args);
System.out.println("CglibProxy after");
return result;
}
}
客户端:
public class Client {
public static void main(String[] args) {
RealSubject realSubject = new RealSubject();
CglibProxy cglibProxy = new CglibProxy(realSubject);
RealSubject proxy = (RealSubject) cglibProxy.getProxy();
proxy.request();
}
}
以上是代理模式的三种实现方式的示例。通过代理模式,可以实现对目标对象的控制,从而实现对系统的控制和管理。
行为型模式
行为型模式关注对象之间的通信,可以根据通信方式分为以下几类:
责任链模式
责任链模式是一种行为型模式,用于将请求沿着处理链发送,直到找到可以处理请求的对象为止。
责任链模式是一种行为型设计模式,其目的是将请求沿着一个链传递,直到有一个对象处理该请求为止。责任链模式允许多个对象都有机会处理请求,避免了请求发送者和接收者之间的耦合。
责任链模式的实现方式有以下几种:
-
单向链表:将所有的处理器按照顺序依次连接起来,形成一条链表,请求从头开始沿着链表传递,直到有一个处理器处理该请求为止。
-
递归方式:将所有的处理器按照顺序依次传递,当有一个处理器处理不了该请求时,将请求传递给下一个处理器,直到有一个处理器处理该请求为止。
以下是两种实现方式的示例:
- 单向链表方式:
抽象处理器类:
public abstract class Handler {
protected Handler successor;
public void setSuccessor(Handler successor) {
this.successor = successor;
}
public abstract void handleRequest(int request);
}
具体处理器类:
public class ConcreteHandler1 extends Handler {
@Override
public void handleRequest(int request) {
if (request < 10) {
System.out.println("ConcreteHandler1 handle request " + request);
} else if (successor != null) {
successor.handleRequest(request);
}
}
}
public class ConcreteHandler2 extends Handler {
@Override
public void handleRequest(int request) {
if (request >= 10 && request < 20) {
System.out.println("ConcreteHandler2 handle request " + request);
} else if (successor != null) {
successor.handleRequest(request);
}
}
}
public class ConcreteHandler3 extends Handler {
@Override
public void handleRequest(int request) {
if (request >= 20) {
System.out.println("ConcreteHandler3 handle request " + request);
} else if (successor != null) {
successor.handleRequest(request);
}
}
}
客户端:
public class Client {
public static void main(String[] args) {
Handler handler1 = new ConcreteHandler1();
Handler handler2 = new ConcreteHandler2();
Handler handler3 = new ConcreteHandler3();
handler1.setSuccessor(handler2);
handler2.setSuccessor(handler3);
int[] requests = {5, 15, 25};
for (int request : requests) {
handler1.handleRequest(request);
}
}
}
- 递归方式:
处理器接口:
public interface Handler {
boolean handleRequest(int request);
}
具体处理器类:
public class ConcreteHandler1 implements Handler {
@Override
public boolean handleRequest(int request) {
if (request < 10) {
System.out.println("ConcreteHandler1 handle request " + request);
return true;
} else {
return false;
}
}
}
public class ConcreteHandler2 implements Handler {
@Override
public boolean handleRequest(int request) {
if (request >= 10 && request < 20) {
System.out.println("ConcreteHandler2 handle request " + request);
return true;
} else {
return false;
}
}
}
public class ConcreteHandler3 implements Handler {
@Override
public boolean handleRequest(int request) {
if (request >= 20) {
System.out.println("ConcreteHandler3 handle request " + request);
return true;
} else {
return false;
}
}
}
客户端:
public class Client {
private static void handleRequest(Handler handler, int request) {
if (!handler.handleRequest(request) && handler instanceof ConcreteHandler) {
handleRequest(((ConcreteHandler) handler).getSuccessor(), request);
}
}
public static void main(String[] args) {
Handler handler1 = new ConcreteHandler1();
Handler handler2 = new ConcreteHandler2();
Handler handler3 = new ConcreteHandler3();
((ConcreteHandler) handler1).setSuccessor(handler2);
((ConcreteHandler) handler2).setSuccessor(handler3);
int[] requests = {5, 15, 25};
for (int request : requests) {
handleRequest(handler1, request);
}
}
}
以上是责任链模式的两种实现方式的示例。责任链模式可以让请求的
命令模式
命令模式是一种行为型模式,用于将请求转换为对象,从而使您可以将不同的请求与不同的接收者解耦。
命令模式是一种行为型设计模式,其目的是将请求封装成对象,从而允许我们使用不同的请求、队列或日志来参数化其他对象。命令模式也支持可撤销操作。
命令模式的实现方式有以下几种:
-
使用接口:定义一个接口来表示具体命令,每个具体命令都实现该接口中的执行方法。
-
使用抽象类:定义一个抽象类来表示具体命令,每个具体命令都继承该抽象类,并实现其中的执行方法。
-
使用 Lambda 表达式:使用 Lambda 表达式来表示具体命令,将 Lambda 表达式传递给接收者对象,从而实现命令的执行。
以下是三种实现方式的示例:
- 使用接口:
命令接口:
public interface Command {
void execute();
}
具体命令类:
public class ConcreteCommand1 implements Command {
private Receiver receiver;
public ConcreteCommand1(Receiver receiver) {
this.receiver = receiver;
}
@Override
public void execute() {
receiver.action1();
}
}
public class ConcreteCommand2 implements Command {
private Receiver receiver;
public ConcreteCommand2(Receiver receiver) {
this.receiver = receiver;
}
@Override
public void execute() {
receiver.action2();
}
}
接收者类:
public class Receiver {
public void action1() {
System.out.println("Receiver action1");
}
public void action2() {
System.out.println("Receiver action2");
}
}
客户端:
public class Client {
public static void main(String[] args) {
Receiver receiver = new Receiver();
Command command1 = new ConcreteCommand1(receiver);
Command command2 = new ConcreteCommand2(receiver);
Invoker invoker = new Invoker();
invoker.setCommand(command1);
invoker.executeCommand();
invoker.setCommand(command2);
invoker.executeCommand();
}
}
- 使用抽象类:
命令抽象类:
public abstract class Command {
protected Receiver receiver;
public Command(Receiver receiver) {
this.receiver = receiver;
}
public abstract void execute();
}
具体命令类:
public class ConcreteCommand1 extends Command {
public ConcreteCommand1(Receiver receiver) {
super(receiver);
}
@Override
public void execute() {
receiver.action1();
}
}
public class ConcreteCommand2 extends Command {
public ConcreteCommand2(Receiver receiver) {
super(receiver);
}
@Override
public void execute() {
receiver.action2();
}
}
接收者类:
public class Receiver {
public void action1() {
System.out.println("Receiver action1");
}
public void action2() {
System.out.println("Receiver action2");
}
}
客户端:
public class Client {
public static void main(String[] args) {
Receiver receiver = new Receiver();
Command command1 = new ConcreteCommand1(receiver);
Command command2 = new ConcreteCommand2(receiver);
Invoker invoker = new Invoker();
invoker.setCommand(command1);
invoker.executeCommand();
invoker.setCommand(command2);
invoker.executeCommand();
}
}
- 使用 Lambda 表达式:
接收者类:
public class Receiver {
public void action1() {
System.out.println("Receiver action1");
}
public void action2() {
System.out.println("Receiver action2");
}
}
客户端:
public class Client {
public static void main(String[] args) {
Receiver receiver = new Receiver();
Invoker invoker = new Invoker();
invoker.setCommand(() -> receiver.action1());
invoker.executeCommand();
invoker.setCommand(() -> receiver.action2());
invoker.executeCommand();
}
}
- 使用注解:在命令模式中使用注解,可以将命令的执行方法与注解绑定,从而实现命令的执行。
命令接口:
public interface Command {
void execute();
}
具体命令类:
public class ConcreteCommand1 implements Command {
@Override
@CommandAnnotation("action1")
public void execute() {
System.out.println("ConcreteCommand1 execute");
}
}
public class ConcreteCommand2 implements Command {
@Override
@CommandAnnotation("action2")
public void execute() {
System.out.println("ConcreteCommand2 execute");
}
}
接收者类:
public class Receiver {
@CommandAnnotation("action1")
public void action1() {
System.out.println("Receiver action1");
}
@CommandAnnotation("action2")
public void action2() {
System.out.println("Receiver action2");
}
}
命令执行器类:
public class CommandExecutor {
private Receiver receiver;
public CommandExecutor(Receiver receiver) {
this.receiver = receiver;
}
public void execute(Command command) {
Method[] methods = receiver.getClass().getDeclaredMethods();
for (Method method : methods) {
CommandAnnotation annotation = method.getAnnotation(CommandAnnotation.class);
if (annotation != null && annotation.value().equals(command.getClass().getSimpleName())) {
try {
method.invoke(receiver);
} catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
e.printStackTrace();
}
break;
}
}
}
}
客户端:
public class Client {
public static void main(String[] args) {
Receiver receiver = new Receiver();
Command command1 = new ConcreteCommand1();
Command command2 = new ConcreteCommand2();
CommandExecutor executor = new CommandExecutor(receiver);
executor.execute(command1);
executor.execute(command2);
}
}
- 使用函数式接口:在 Java 8 中,可以使用函数式接口来实现命令模式,例如使用 Runnable 接口来表示具体命令的执行方法。
具体命令类:
public class ConcreteCommand1 implements Runnable {
private Receiver receiver;
public ConcreteCommand1(Receiver receiver) {
this.receiver = receiver;
}
@Override
public void run() {
receiver.action1();
}
}
public class ConcreteCommand2 implements Runnable {
private Receiver receiver;
public ConcreteCommand2(Receiver receiver) {
this.receiver = receiver;
}
@Override
public void run() {
receiver.action2();
}
}
接收者类:
public class Receiver {
public void action1() {
System.out.println("Receiver action1");
}
public void action2() {
System.out.println("Receiver action2");
}
}
命令执行器类:
public class CommandExecutor {
public void execute(Runnable command) {
command.run();
}
}
客户端:
public class Client {
public static void main(String[] args) {
Receiver receiver = new Receiver();
Runnable command1 = new ConcreteCommand1(receiver);
Runnable command2 = new ConcreteCommand2(receiver);
CommandExecutor executor = new CommandExecutor();
executor.execute(command1);
executor.execute(command2);
}
}
- 使用反射:在命令模式中使用反射,可以将命令的执行方法与方法名绑定,从而实现命令的执行。
命令接口:
public interface Command {
void execute();
}
具体命令类:
public class ConcreteCommand1 implements Command {
@Override
public void execute() {
System.out.println("ConcreteCommand1 execute");
}
}
public class ConcreteCommand2 implements Command {
@Override
public void execute() {
System.out.println("ConcreteCommand2 execute");
}
}
接收者类:
public class Receiver {
public void action1() {
System.out.println("Receiver action1");
}
public void action2() {
System.out.println("Receiver action2");
}
}
命令执行器类:
public class CommandExecutor {
private Receiver receiver;
public CommandExecutor(Receiver receiver) {
this.receiver = receiver;
}
public void execute(Command command) {
try {
Method method = receiver.getClass().getMethod(command.getClass().getSimpleName().toLowerCase());
method.invoke(receiver);
} catch (NoSuchMethodException | SecurityException | IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
e.printStackTrace();
}
}
}
客户端:
public class Client {
public static void main(String[] args) {
Receiver receiver = new Receiver();
Command command1 = new ConcreteCommand1();
Command command2 = new ConcreteCommand2();
CommandExecutor executor = new CommandExecutor(receiver);
executor.execute(command1);
executor.execute(command2);
}
}
- 使用 Lambda 表达式:在 Java 8 中,可以使用 Lambda 表达式来实现命令模式,例如使用 Runnable 接口来表示具体命令的执行方法。
具体命令类:
public class ConcreteCommand1 implements Runnable {
@Override
public void run() {
System.out.println("ConcreteCommand1 execute");
}
}
public class ConcreteCommand2 implements Runnable {
@Override
public void run() {
System.out.println("ConcreteCommand2 execute");
}
}
接收者类:
public class Receiver {
public void action1() {
System.out.println("Receiver action1");
}
public void action2() {
System.out.println("Receiver action2");
}
}
命令执行器类:
public class CommandExecutor {
private Receiver receiver;
public CommandExecutor(Receiver receiver) {
this.receiver = receiver;
}
public void execute(Runnable command) {
command.run();
}
}
客户端:
public class Client {
public static void main(String[] args) {
Receiver receiver = new Receiver();
Runnable command1 = () -> receiver.action1();
Runnable command2 = () -> receiver.action2();
CommandExecutor executor = new CommandExecutor(receiver);
executor.execute(command1);
executor.execute(command2);
}
}
这里是第四部分。
- 使用 Java 8 的 Method Reference:在 Java 8 中,可以使用 Method Reference 来实现命令模式,例如使用方法引用来表示具体命令的执行方法。
具体命令类:
public class ConcreteCommand1 {
public void execute() {
System.out.println("ConcreteCommand1 execute");
}
}
public class ConcreteCommand2 {
public void execute() {
System.out.println("ConcreteCommand2 execute");
}
}
接收者类:
public class Receiver {
public void action1() {
System.out.println("Receiver action1");
}
public void action2() {
System.out.println("Receiver action2");
}
}
命令执行器类:
public class CommandExecutor {
private Receiver receiver;
public CommandExecutor(Receiver receiver) {
this.receiver = receiver;
}
public void execute(Runnable command) {
command.run();
}
}
客户端:
public class Client {
public static void main(String[] args) {
Receiver receiver = new Receiver();
ConcreteCommand1 command1 = new ConcreteCommand1();
ConcreteCommand2 command2 = new ConcreteCommand2();
CommandExecutor executor = new CommandExecutor(receiver);
executor.execute(receiver::action1);
executor.execute(receiver::action2);
executor.execute(command1::execute);
executor.execute(command2::execute);
}
}
- 使用函数式接口的默认方法:在 Java 8 中,可以使用函数式接口的默认方法来实现命令模式。
命令接口:
public interface Command {
default void execute(Receiver receiver) {
System.out.println("Command execute");
}
}
具体命令类:
public class ConcreteCommand1 implements Command {
@Override
public void execute(Receiver receiver) {
System.out.println("ConcreteCommand1 execute");
receiver.action1();
}
}
public class ConcreteCommand2 implements Command {
@Override
public void execute(Receiver receiver) {
System.out.println("ConcreteCommand2 execute");
receiver.action2();
}
}
接收者类:
public class Receiver {
public void action1() {
System.out.println("Receiver action1");
}
public void action2() {
System.out.println("Receiver action2");
}
}
命令执行器类:
public class CommandExecutor {
public void execute(Command command, Receiver receiver) {
command.execute(receiver);
}
}
客户端:
public class Client {
public static void main(String[] args) {
Receiver receiver = new Receiver();
Command command1 = new ConcreteCommand1();
Command command2 = new ConcreteCommand2();
CommandExecutor executor = new CommandExecutor();
executor.execute(receiver::action1, receiver);
executor.execute(receiver::action2, receiver);
executor.execute(command1::execute, receiver);
executor.execute(command2::execute, receiver);
}
}
以上是几种常见的命令模式的实现方式,在实际应用中,需要根据具体的场景选择合适的实现方式。
解释器模式
解释器模式是一种基于文法规则的解释器,用于解释一种语言或表达式。它将一个特定的语言解释成为另一种语言,并且可以根据不同的文法规则生成不同的解释器。
解释器模式有两种主要的实现方式:
-
递归下降解析器:这种实现方式通过递归调用来解析语法树。它首先识别语法的顶层元素,然后逐层向下解析,直到解析整个语法树。这种实现方式比较简单,并且易于理解和实现。例如,一个简单的四则运算表达式可以用递归下降解析器来实现。
-
语法制导翻译器:这种实现方式是一种更为复杂的解释器实现方式,它使用语法制导翻译技术来解析语法树。语法制导翻译器使用上下文无关文法来描述语言,将语法规则与执行代码相结合。这种实现方式可以生成更为高效的代码,并且可以应用于更为复杂的语言。
-
下面是一个简单的Java递归下降解析器的示例,用于解析一个简单的四则运算表达式:
首先,我们定义一个 Expression
接口,它包含一个 interpret
方法,用于解析表达式。然后我们定义两个子类 NumberExpression
和 OperatorExpression
,分别表示数字和操作符。其中,OperatorExpression
包含两个子类 AddExpression
、SubtractExpression
、MultiplyExpression
和 DivideExpression
,分别表示加、减、乘和除四种运算操作。
interface Expression {
int interpret();
}
class NumberExpression implements Expression {
private int value;
public NumberExpression(int value) {
this.value = value;
}
@Override
public int interpret() {
return value;
}
}
class OperatorExpression implements Expression {
private Expression left;
private Expression right;
public OperatorExpression(Expression left, Expression right) {
this.left = left;
this.right = right;
}
}
class AddExpression extends OperatorExpression {
public AddExpression(Expression left, Expression right) {
super(left, right);
}
@Override
public int interpret() {
return left.interpret() + right.interpret();
}
}
class SubtractExpression extends OperatorExpression {
public SubtractExpression(Expression left, Expression right) {
super(left, right);
}
@Override
public int interpret() {
return left.interpret() - right.interpret();
}
}
class MultiplyExpression extends OperatorExpression {
public MultiplyExpression(Expression left, Expression right) {
super(left, right);
}
@Override
public int interpret() {
return left.interpret() * right.interpret();
}
}
class DivideExpression extends OperatorExpression {
public DivideExpression(Expression left, Expression right) {
super(left, right);
}
@Override
public int interpret() {
return left.interpret() / right.interpret();
}
}
在上述代码中,我们定义了一个 Expression
接口,它包含一个 interpret
方法,用于解析表达式。NumberExpression
表示数字,OperatorExpression
表示操作符,包含左右两个子表达式。AddExpression
、SubtractExpression
、MultiplyExpression
和 DivideExpression
是 OperatorExpression
的子类,分别表示加、减、乘和除四种运算操作。这些子类实现了 interpret
方法,根据不同的运算符来执行相应的运算操作。
接下来,我们定义一个 Parser
类,用于解析整个表达式:
class Parser {
private List<String> tokens;
private int index;
public Parser(String input) {
tokens = Arrays.asList(input.split("\\s+"));
index = 0;
}
public Expression parse() {
Expression left = parseTerm();
while (index < tokens.size()) {
String operator = tokens.get(index);
if (!("+".equals(operator) || "-".equals(operator) || "*".equals(operator) || "/".equals(operator))) {
throw new IllegalArgumentException("Unexpected operator: " + operator);
}
index++;
Expression right = parseTerm();
switch (operator) {
case "+":
left = new AddExpression(left, right);
break;
case "-":
left = new SubtractExpression(left, right);
break;
case "*":
left = new MultiplyExpression(left, right);
break;
case "/":
left = new DivideExpression(left, right);
break;
}
}
return left;
}
private Expression parseTerm() {
String token = tokens.get(index);
index++;
try {
int value = Integer.parseInt(token);
return new NumberExpression(value);
} catch (NumberFormatException e) {
throw new IllegalArgumentException("Invalid number: " + token);
}
}
}
在上述代码中,我们定义了一个 Parser
类,它接受一个字符串作为输入,将其分割成一个个的单词(token),然后依次解析每个单词。parse
方法用于解析整个表达式,它首先解析第一个子表达式 left
,然后循环解析接下来的操作符和子表达式,直到所有单词都被解析完成。parseTerm
方法用于解析一个子表达式,它首先解析一个单词,如果是数字则创建一个 NumberExpression
实例,否则抛出异常。
最后,我们可以使用上述代码来解析一个简单的四则运算表达式,例如 "1 + 2 * 3 - 4 / 2"
:
Parser parser = new Parser("1 + 2 * 3 - 4 / 2");
Expression expression = parser.parse();
int result = expression.interpret();
System.out.println(result); // 输出 5
在上述代码中,我们首先创建一个 Parser
实例,然后调用 parse
方法解析表达式,得到一个 Expression
实例,最后调用 interpret
方法计算表达式的结果,并输出结果。上述表达式的结果应该是 5
,因为它等价于 (1 + (2 * 3)) - (4 / 2)
。
- 使用解释器模式来解析一个简单的SQL查询语句,该语句包含两个关键字
SELECT
和FROM
,以及一个表名和一个列名。
首先,我们定义一个 Expression
接口,它包含一个 interpret
方法,用于解析表达式。然后我们定义两个子类 SelectExpression
和 FromExpression
,分别表示 SELECT
和 FROM
关键字。每个子类都包含一个 String
类型的参数,用于表示表名或列名。
interface Expression {
String interpret(Context context);
}
class SelectExpression implements Expression {
private String column;
public SelectExpression(String column) {
this.column = column;
}
@Override
public String interpret(Context context) {
return "SELECT " + column + " FROM " + context.getTable();
}
}
class FromExpression implements Expression {
private String table;
public FromExpression(String table) {
this.table = table;
}
@Override
public String interpret(Context context) {
context.setTable(table);
return "";
}
}
在上述代码中,我们定义了两个子类 SelectExpression
和 FromExpression
,分别用于解析 SELECT
和 FROM
关键字。每个子类都实现了 Expression
接口,并且包含一个 String
类型的参数,用于表示表名或列名。SelectExpression
的 interpret
方法返回一个字符串,表示解析后的查询语句;而 FromExpression
的 interpret
方法则将表名存储在上下文中,并返回一个空字符串。
接下来,我们定义一个 Context
类,用于存储解析过程中的上下文信息。
class Context {
private String table;
public Context() {
this.table = "";
}
public String getTable() {
return table;
}
public void setTable(String table) {
this.table = table;
}
}
在上述代码中,我们定义了一个 table
字段,用于存储表名。
最后,我们定义一个 Interpreter
类,用于解析整个查询语句。
class Interpreter {
private Expression expression;
public Interpreter(Expression expression) {
this.expression = expression;
}
public String interpret(Context context) {
return expression.interpret(context);
}
}
在上述代码中,我们定义了一个 Interpreter
类,它包含一个 Expression
类型的字段,用于表示需要解析的查询语句。interpret
方法接受一个上下文对象,并调用 Expression
类型的 interpret
方法来解析查询语句。
现在,我们可以使用上述类来解析一个简单的查询语句了。下面是示例代码:
public class Main {
public static void main(String[] args) {
Context context = new Context();
Expression expression = new SelectExpression("name");
Interpreter interpreter = new Interpreter(expression);
String query = interpreter.interpret(context);
System.out.println(query); // Output: SELECT name FROM
expression = new FromExpression("users");
interpreter = new Interpreter(expression);
query = interpreter.interpret(context);
System.out.println(query); // Output:
query = interpreter.interpret(context);
System.out.println(query); // Output: SELECT name FROM users
}
}
在上述代码中,我们首先创建了一个 Context
对象,然后使用 SelectExpression
类来解析列名,使用 FromExpression
类来解析表名。最后,我们将两个解析结果合并在一起,得到完整的查询语句。
以下是一个简单的Java语法制导翻译器实现方式的示例:
首先,我们定义一个 Expression
接口,它包含一个 interpret
方法,用于解释表达式。然后我们定义两个子类 NumberExpression
和 OperatorExpression
,分别表示数字和操作符。其中,OperatorExpression
包含四个子类 AddExpression
、SubtractExpression
、MultiplyExpression
和 DivideExpression
,分别表示加、减、乘和除四种运算操作。
interface Expression {
int interpret();
}
class NumberExpression implements Expression {
private int value;
public NumberExpression(int value) {
this.value = value;
}
@Override
public int interpret() {
return value;
}
}
class OperatorExpression implements Expression {
private Expression left;
private Expression right;
public OperatorExpression(Expression left, Expression right) {
this.left = left;
this.right = right;
}
public Expression getLeft() {
return left;
}
public Expression getRight() {
return right;
}
}
class AddExpression extends OperatorExpression {
public AddExpression(Expression left, Expression right) {
super(left, right);
}
@Override
public int interpret() {
return getLeft().interpret() + getRight().interpret();
}
}
class SubtractExpression extends OperatorExpression {
public SubtractExpression(Expression left, Expression right) {
super(left, right);
}
@Override
public int interpret() {
return getLeft().interpret() - getRight().interpret();
}
}
class MultiplyExpression extends OperatorExpression {
public MultiplyExpression(Expression left, Expression right) {
super(left, right);
}
@Override
public int interpret() {
return getLeft().interpret() * getRight().interpret();
}
}
class DivideExpression extends OperatorExpression {
public DivideExpression(Expression left, Expression right) {
super(left, right);
}
@Override
public int interpret() {
return getLeft().interpret() / getRight().interpret();
}
}
然后,我们可以使用上述代码来解析一个简单的四则运算表达式,例如 "1 + 2 * 3 - 4 / 2"
:
Expression expression = new SubtractExpression(
new AddExpression(
new NumberExpression(1),
new MultiplyExpression(
new NumberExpression(2),
new NumberExpression(3)
)
),
new DivideExpression(
new NumberExpression(4),
new NumberExpression(2)
)
);
int result = expression.interpret();
System.out.println(result); // 输出 5
在上述代码中,我们首先创建了一个 SubtractExpression
对象,它包含一个 AddExpression
和一个 DivideExpression
对象。AddExpression
对象又包含一个 NumberExpression
和一个 MultiplyExpression
对象。MultiplyExpression
对象又包含两个 NumberExpression
对象。最后,我们调用 interpret
方法来解释整个表达式,并输出结果。
迭代器模式
迭代器模式是一种行为型模式,用于提供一种方法来访问聚合对象中的元素,而不需要暴露其内部表示。
在Java中,迭代器模式也是一种常用的设计模式,以下是几种实现迭代模式的方式:
- 迭代器模式
迭代器模式是一种将集合与遍历分离的设计模式。在Java中,迭代器模式通常使用 Iterator 接口来实现。Iterator 接口包含 hasNext() 和 next() 两个方法,分别用于检查是否有下一个元素和获取下一个元素。以下是一个示例:
// 定义迭代器接口
public interface Iterator<T> {
boolean hasNext();
T next();
}
// 实现一个数组迭代器
public class ArrayIterator<T> implements Iterator<T> {
private T[] array;
private int position = 0;
public ArrayIterator(T[] array) {
this.array = array;
}
public boolean hasNext() {
return position < array.length;
}
public T next() {
if (!hasNext()) {
throw new NoSuchElementException();
}
return array[position++];
}
}
// 使用迭代器遍历数组
public static void main(String[] args) {
Integer[] array = {1, 2, 3};
Iterator<Integer> iterator = new ArrayIterator<>(array);
while (iterator.hasNext()) {
Integer element = iterator.next();
System.out.println(element);
}
}
- 增强 for 循环
增强 for 循环是一种简化迭代操作的语法结构,它可以用于遍历数组、集合等实现了 Iterable 接口的对象。以下是一个示例:
// 使用增强 for 循环遍历数组
public static void main(String[] args) {
Integer[] array = {1, 2, 3};
for (Integer element : array) {
System.out.println(element);
}
}
- Stream API
Stream API 是 Java 8 中引入的一个用于处理集合和数组的 API,它提供了一种简单而强大的方法来对集合中的元素进行过滤、转换和聚合等操作。Stream API 中的 forEach() 方法可以用于遍历流中的元素。以下是一个示例:
// 使用 Stream API 遍历数组
public static void main(String[] args) {
Integer[] array = {1, 2, 3};
Arrays.stream(array).forEach(System.out::println);
}
以上是几种常见的实现迭代模式的方式,在实际开发中可以根据具体的需求选择合适的方法。
中介者模式
中介者模式是一种行为型模式,用于封装一组对象之间的交互方式。中介者使对象之间不需要显式地相互引用,从而降低了它们之间的耦合度。
Java中介者模式主要有两种实现方式:
- 中央调度器实现方式
中央调度器实现方式中,我们定义一个中央调度器(也称为中介者),它负责协调各个对象之间的交互。具体来说,每个对象都将自己注册到中央调度器,并在需要与其他对象交互时,向中央调度器发送请求。中央调度器接收到请求后,根据请求的内容,协调各个对象之间的交互。这种实现方式比较简单,但可能会导致中央调度器过于复杂。
以下是一个中央调度器实现方式的示例:
interface Mediator {
void register(Colleague colleague);
void send(String message, Colleague sender);
}
abstract class Colleague {
protected Mediator mediator;
public void setMediator(Mediator mediator) {
this.mediator = mediator;
}
public abstract void receive(String message);
}
class ConcreteMediator implements Mediator {
private List<Colleague> colleagues = new ArrayList<>();
@Override
public void register(Colleague colleague) {
colleagues.add(colleague);
colleague.setMediator(this);
}
@Override
public void send(String message, Colleague sender) {
for (Colleague colleague : colleagues) {
if (colleague != sender) {
colleague.receive(message);
}
}
}
}
class ConcreteColleague extends Colleague {
private String name;
public ConcreteColleague(String name) {
this.name = name;
}
@Override
public void receive(String message) {
System.out.println(name + " received message: " + message);
}
public void send(String message) {
mediator.send(message, this);
}
}
public class MediatorExample {
public static void main(String[] args) {
Mediator mediator = new ConcreteMediator();
Colleague colleague1 = new ConcreteColleague("Colleague 1");
Colleague colleague2 = new ConcreteColleague("Colleague 2");
Colleague colleague3 = new ConcreteColleague("Colleague 3");
mediator.register(colleague1);
mediator.register(colleague2);
mediator.register(colleague3);
colleague1.send("Hello, colleagues!");
}
}
- 观察者模式实现方式
观察者模式实现方式中,我们定义一个主题接口和一个观察者接口。每个对象都可以同时充当主题和观察者,当自己的状态发生改变时,它会通知其他对象,这些对象也可以再次通知其他对象,形成一个观察者链。这种实现方式比较灵活,但可能会导致对象之间的交互过于复杂。
以下是一个观察者模式实现方式的示例:
interface Subject {
void registerObserver(Observer observer);
void removeObserver(Observer observer);
void notifyObservers(String message);
}
interface Observer {
void update(String message);
}
class ConcreteSubject implements Subject {
private List<Observer> observers = new ArrayList<>();
@Override
public void registerObserver(Observer observer) {
observers.add(observer);
}
@Override
public void removeObserver(Observer observer) {
observers.remove(observer);
}
@Override
public void notifyObservers(String message) {
for (Observer observer : observers) {
observer.update(message);
}
}
}
class ConcreteObserver implements Observer {
private String name;
public ConcreteObserver(String name) {
this.name = name;
}
@Override
public void update(String message) {
System.out.println(name + " received message: " + message);
}
}
public class ObserverExample {
public static void main(String[] args) {
Subject subject = new ConcreteSubject();
Observer observer1 = new ConcreteObserver("Observer 1");
Observer observer2 = new ConcreteObserver("Observer 2");
Observer observer3 = new ConcreteObserver("Observer 3");
subject.registerObserver(observer1);
subject.registerObserver(observer2);
subject.registerObserver(observer3);
subject.notifyObservers("Hello, observers!");
}
}
在上述示例中,我们定义了一个主题接口 Subject
和一个观察者接口 Observer
。我们还定义了一个具体的主题类 ConcreteSubject
,它实现了 Subject
接口,并维护了一个观察者列表,用于存储所有注册到主题中的观察者。当主题状态发生改变时,它会通知所有观察者。我们还定义了一个具体的观察者类 ConcreteObserver
,它实现了 Observer
接口,并实现了 update
方法,用于接收来自主题的通知并做出相应的处理。在 main
方法中,我们创建了一个主题对象和三个观察者对象,并将它们注册到主题中。然后,我们使用 notifyObservers
方法通知所有观察者对象。当主题对象通知观察者对象时,观察者对象会接收到消息并做出相应的处理。
需要注意的是,观察者模式实现方式中,主题对象和观察者对象之间的交互是双向的,也就是说,主题对象可以直接调用观察者对象的方法。而在中央调度器实现方式中,所有对象之间的交互都是通过中央调度器来实现的,对象之间不能直接调用对方的方法。
备忘录模式
备忘录模式是一种行为型模式,用于捕获并存储一个对象的状态,以后可以恢复该状态。
Java备忘录模式主要有两种实现方式:
- 普通备忘录模式
普通备忘录模式中,我们定义一个备忘录对象来保存原始对象的状态。具体来说,我们创建一个备忘录类,它包含原始对象的状态信息,并提供获取和设置状态信息的方法。然后,我们创建一个原始对象类,它包含需要保存的状态信息,并提供创建备忘录和恢复状态的方法。这种实现方式比较简单,但可能会导致备忘录对象过于复杂。
以下是一个普通备忘录模式的示例:
class Memento {
private String state;
public Memento(String state) {
this.state = state;
}
public String getState() {
return state;
}
public void setState(String state) {
this.state = state;
}
}
class Originator {
private String state;
public void setState(String state) {
this.state = state;
}
public String getState() {
return state;
}
public Memento createMemento() {
return new Memento(state);
}
public void restoreMemento(Memento memento) {
state = memento.getState();
}
}
class Caretaker {
private Memento memento;
public void setMemento(Memento memento) {
this.memento = memento;
}
public Memento getMemento() {
return memento;
}
}
public class MementoExample {
public static void main(String[] args) {
Originator originator = new Originator();
Caretaker caretaker = new Caretaker();
originator.setState("State 1");
System.out.println("Current state: " + originator.getState());
caretaker.setMemento(originator.createMemento());
originator.setState("State 2");
System.out.println("Current state: " + originator.getState());
originator.restoreMemento(caretaker.getMemento());
System.out.println("Current state: " + originator.getState());
}
}
在上述示例中,我们定义了一个备忘录类 Memento
,它包含了需要保存的状态信息,并提供了获取和设置状态信息的方法。我们还定义了一个原始对象类 Originator
,它包含了需要保存的状态信息,并提供了创建备忘录和恢复状态的方法。在 main
方法中,我们创建了一个原始对象和一个备忘录对象,并将原始对象的状态设置为 “State 1”,然后将备忘录对象保存到一个管理类 Caretaker
中。接着,我们将原始对象的状态设置为 “State 2”,并输出当前状态。最后,我们通过 restoreMemento
方法恢复原始对象的状态,并输出当前状态。
- 多状态备忘录模式
多状态备忘录模式中,我们创建一个备忘录类来保存原始对象的多个状态信息。具体来说,我们创建一个备忘录类,它包含多个状态信息,并提供获取和设置状态信息的方法。然后,我们创建一个原始对象类,它包含多个需要保存的状态信息,并提供创建备忘录和恢复状态的方法。这种实现方式相对于普通备忘录模式来说,备忘录对象比较简单,但需要额外维护多个状态信息。
以下是一个多状态备忘录模式的示例:
class Memento {
private String state1;
private String state2;
public Memento(String state1, String state2) {
this.state1 = state1;
this.state2 = state2;
}
public String getState1() {
return state1;
}
public void setState1(String state1) {
this.state1 = state1;
}
public String getState2() {
return state2;
}
public void setState2(String state2) {
this.state2 = state2;
}
}
class Originator {
private String state1;
private String state2;
public void setState1(String state1) {
this.state1 = state1;
}
public String getState1() {
return state1;
}
public void setState2(String state2) {
this.state.state2 = state2;
}
public String getState2() {
return state2;
}
public Memento createMemento() {
return new Memento(state1, state2);
}
public void restoreMemento(Memento memento) {
state1 = memento.getState1();
state2 = memento.getState2();
}
}
class Caretaker {
private List<Memento> mementos = new ArrayList<>();
public void addMemento(Memento memento) {
mementos.add(memento);
}
public Memento getMemento(int index) {
return mementos.get(index);
}
}
public class MementoExample {
public static void main(String[] args) {
Originator originator = new Originator();
Caretaker caretaker = new Caretaker();
originator.setState1("State 1");
originator.setState2("State 2");
System.out.println("Current state: " + originator.getState1() + ", " + originator.getState2());
caretaker.addMemento(originator.createMemento());
originator.setState1("State 3");
originator.setState2("State 4");
System.out.println("Current state: " + originator.getState1() + ", " + originator.getState2());
caretaker.addMemento(originator.createMemento());
originator.restoreMemento(caretaker.getMemento(0));
System.out.println("Current state: " + originator.getState1() + ", " + originator.getState2());
originator.restoreMemento(caretaker.getMemento(1));
System.out.println("Current state: " + originator.getState1() + ", " + originator.getState2());
}
}
在上述示例中,我们定义了一个备忘录类 Memento
,它包含了需要保存的多个状态信息,并提供了获取和设置状态信息的方法。我们还定义了一个原始对象类 Originator
,它包含了多个需要保存的状态信息,并提供了创建备忘录和恢复状态的方法。在 main
方法中,我们创建了一个原始对象和一个管理类 Caretaker
,并将原始对象的两个状态分别设置为 “State 1” 和 “State 2”,然后将备忘录对象保存到管理类中。接着,我们将原始对象的两个状态分别设置为 “State 3” 和 “State 4”,并输出当前状态。然后,我们通过 restoreMemento
方法恢复原始对象的状态,并输出当前状态。通过这种方式,我们可以保存多个状态信息,并在需要时恢复到任意一个状态。
观察者模式
观察者模式是一种行为型模式,用于在对象之间定义一对多的依赖关系,以便当一个对象的状态发生变化时,所有依赖于它的对象都可以得到通知并自动更新。
Java观察者模式有两种常见的实现方式:JDK内置观察者模式和自定义观察者模式。
- JDK内置观察者模式
在Java的标准库中,提供了内置的观察者模式实现。具体来说,我们可以通过 java.util.Observable
类和 java.util.Observer
接口来实现观察者模式。Observable
类表示被观察者,它包含了一个观察者列表和相关的方法,比如添加和删除观察者、通知观察者等。Observer
接口表示观察者,它包含了一个更新方法,被观察者在状态发生变化时会调用该方法通知观察者。
以下是一个使用JDK内置观察者模式的示例:
import java.util.Observable;
import java.util.Observer;
class WeatherData extends Observable {
private float temperature;
private float humidity;
private float pressure;
public void measurementsChanged() {
setChanged();
notifyObservers();
}
public void setMeasurements(float temperature, float humidity, float pressure) {
this.temperature = temperature;
this.humidity = humidity;
this.pressure = pressure;
measurementsChanged();
}
public float getTemperature() {
return temperature;
}
public float getHumidity() {
return humidity;
}
public float getPressure() {
return pressure;
}
}
class CurrentConditionsDisplay implements Observer {
private float temperature;
private float humidity;
private float pressure;
public void update(Observable obs, Object arg) {
if (obs instanceof WeatherData) {
WeatherData weatherData = (WeatherData) obs;
this.temperature = weatherData.getTemperature();
this.humidity = weatherData.getHumidity();
this.pressure = weatherData.getPressure();
display();
}
}
public void display() {
System.out.println("Current conditions: " + temperature + "F degrees and " + humidity + "% humidity");
}
}
public class WeatherStation {
public static void main(String[] args) {
WeatherData weatherData = new WeatherData();
CurrentConditionsDisplay currentConditionsDisplay = new CurrentConditionsDisplay();
weatherData.addObserver(currentConditionsDisplay);
weatherData.setMeasurements(80, 65, 30.4f);
}
}
在上述示例中,我们定义了一个被观察者类 WeatherData
,它继承自 Observable
类,并包含了三个状态信息(温度、湿度和气压),以及相关的方法。在状态发生变化时,我们调用 setChanged()
方法标记状态已经改变,并调用 notifyObservers()
方法通知所有观察者。接着,我们定义了一个观察者类 CurrentConditionsDisplay
,它实现了 Observer
接口,并包含了一个更新方法和一个显示方法。在更新方法中,我们获取被观察者的状态信息,并更新当前状态。在显示方法中,我们输出当前状态信息。在 main
方法中,我们首先创建了一个被观察者对象和一个观察者对象,然后将观察者对象注册到被观察者对象中,并设置状态信息。通过这种方式,我们可以实现多个观察者同时观察一个被观察者,并在状态发生变化时自动更新。
- 自定义观察者模式
除了使用JDK内置观察者模式外,我们也可以自己实现观察者模式。具体来说,我们需要定义一个观察者接口和一个被观察者接口,以及相关的具体类。观察者接口包含了一个更新方法,被观察者接口包含了注册、删除和通知观察者的方法。具体的观察者类和被观察者类实现这两个接口,并在具体实现中完成状态的更新和通知。
以下是一个自定义观察者模式的示例:
interface Observer {
void update(float temperature, float humidity, floatpressure);
}
interface Subject {
void registerObserver(Observer o);
void removeObserver(Observer o);
void notifyObservers();
}
class WeatherData implements Subject {
private float temperature;
private float humidity;
private float pressure;
private List<Observer> observers;
public WeatherData() {
observers = new ArrayList<>();
}
public void registerObserver(Observer o) {
observers.add(o);
}
public void removeObserver(Observer o) {
int index = observers.indexOf(o);
if (index >= 0) {
observers.remove(index);
}
}
public void notifyObservers() {
for (Observer o : observers) {
o.update(temperature, humidity, pressure);
}
}
public void measurementsChanged() {
notifyObservers();
}
public void setMeasurements(float temperature, float humidity, float pressure) {
this.temperature = temperature;
this.humidity = humidity;
this.pressure = pressure;
measurementsChanged();
}
}
class CurrentConditionsDisplay implements Observer {
private float temperature;
private float humidity;
private float pressure;
private Subject weatherData;
public CurrentConditionsDisplay(Subject weatherData) {
this.weatherData = weatherData;
weatherData.registerObserver(this);
}
public void update(float temperature, float humidity, float pressure) {
this.temperature = temperature;
this.humidity = humidity;
this.pressure = pressure;
display();
}
public void display() {
System.out.println("Current conditions: " + temperature + "F degrees and " + humidity + "% humidity");
}
}
public class WeatherStation {
public static void main(String[] args) {
WeatherData weatherData = new WeatherData();
CurrentConditionsDisplay currentConditionsDisplay = new CurrentConditionsDisplay(weatherData);
weatherData.setMeasurements(80, 65, 30.4f);
}
}
在上述示例中,我们定义了一个观察者接口 Observer
和一个被观察者接口 Subject
,以及具体的观察者类 CurrentConditionsDisplay
和被观察者类 WeatherData
。在被观察者类中,我们维护了一个观察者列表,并在注册、删除和通知观察者的方法中完成相应的操作。在具体实现中,我们在状态发生变化时调用 notifyObservers()
方法通知所有观察者。在观察者类中,我们实现了更新方法,并在构造方法中将自己注册到被观察者对象中。在更新方法中,我们获取被观察者的状态信息,并更新当前状态。在 main
方法中,我们首先创建了一个被观察者对象和一个观察者对象,然后将观察者对象注册到被观察者对象中,并设置状态信息。通过这种方式,我们也可以实现多个观察者同时观察一个被观察者,并在状态发生变化时自动更新。
总之,观察者模式是一种常见的设计模式,它可以帮助我们实现对象之间的松耦合,并使得系统更加灵活和可扩展。在Java中,我们可以使用JDK内置观察者模式或自定义观察者模式来实现该模式。根据具体的场景和需求,我们可以选择适合自己的实现方式。
状态模式
状态模式是一种行为型模式,用于通过将对象的行为委托给表示状态的对象,来实现基于状态的行为。
状态模式是一种常见的设计模式,它可以帮助我们实现对象状态的管理和转换,并使得系统更加灵活和可扩展。在Java中,我们可以使用以下几种方式来实现状态模式:
- 使用接口实现状态模式
在这种方式中,我们定义一个接口来表示状态,并在具体状态类中实现该接口。在上下文类中,我们维护一个当前状态对象,并在状态转换时更新该状态对象。以下是一个示例:
interface State {
void handle();
}
class ConcreteStateA implements State {
public void handle() {
System.out.println("Handle ConcreteStateA");
}
}
class ConcreteStateB implements State {
public void handle() {
System.out.println("Handle ConcreteStateB");
}
}
class Context {
private State state;
public Context(State state) {
this.state = state;
}
public void setState(State state) {
this.state = state;
}
public void request() {
state.handle();
}
}
public class StateDemo {
public static void main(String[] args) {
State stateA = new ConcreteStateA();
State stateB = new ConcreteStateB();
Context context = new Context(stateA);
context.request();
context.setState(stateB);
context.request();
}
}
在上述示例中,我们定义了一个状态接口 State
和两个具体状态类 ConcreteStateA
和 ConcreteStateB
,在具体状态类中实现了状态处理方法。在上下文类 Context
中,我们维护了一个当前状态对象,并在状态转换时更新该状态对象。在 main
方法中,我们首先创建了两个具体状态对象和一个上下文对象,并设置初始状态为 ConcreteStateA
。通过调用 request()
方法,我们可以根据当前状态执行相应的处理操作。在后续的状态转换中,我们只需要调用 setState()
方法更新当前状态即可。
- 使用枚举实现状态模式
在这种方式中,我们使用枚举类型来表示状态,并在上下文类中维护一个当前状态枚举变量。以下是一个示例:
enum State {
STATE_A {
public void handle() {
System.out.println("Handle State A");
}
},
STATE_B {
public void handle() {
System.out.println("Handle State B");
}
};
public abstract void handle();
}
class Context {
private State state;
public Context(State state) {
this.state = state;
}
public void setState(State state) {
this.state = state;
}
public void request() {
state.handle();
}
}
public class StateDemo {
public static void main(String[] args) {
Context context = new Context(State.STATE_A);
context.request();
context.setState(State.STATE_B);
context.request();
}
}
在上述示例中,我们使用枚举类型来表示状态,并在枚举常量中实现相应的处理方法。在上下文类 Context
中,我们维护了一个当前状态枚举变量,并在状态转换时更新该变量。在 main
方法中,我们首先创建了一个上下文对象,并设置初始状态为 STATE_A
。通过调用 request()
方法,我们可以根据当前状态执行相应的处理操作。在后续的状态转换中,我们只需要调用 setState()
方法更新当前状态即可。
- 使用类继承实现状态模式
在这种方式中,我们使用类继承来表示状态,并在上下文类中维护一个当前状态对象。以下是一个示例:
abstract class State {
protected Context context;
public void setContext(Context context) {
this.context = context;
}
public abstract void handle();
}
class ConcreteStateA extends State {
public void handle() {
System.out.println("Handle ConcreteStateA");
context.setState(new ConcreteStateB());
}
}
class ConcreteStateB extends State {
public void handle() {
System.out.println("Handle ConcreteStateB");
context.setState(new ConcreteStateA());
}
}
class Context {
private State state;
public Context(State state) {
this.state = state;
this.state.setContext(this);
}
public void setState(State state) {this.state = state;
this.state.setContext(this);
}
public void request() {
state.handle();
}
}
public class StateDemo {
public static void main(String[] args) {
State stateA = new ConcreteStateA();
Context context = new Context(stateA);
context.request();
context.request();
context.request();
}
}
在上述示例中,我们定义了一个抽象状态类 State
和两个具体状态类 ConcreteStateA
和 ConcreteStateB
,在具体状态类中实现了状态处理方法,并在方法中调用 setState()
方法来实现状态转换。在上下文类 Context
中,我们维护了一个当前状态对象,并在状态转换时更新该对象。在 main
方法中,我们首先创建了一个具体状态对象和一个上下文对象,并设置初始状态为 ConcreteStateA
。通过调用 request()
方法,我们可以根据当前状态执行相应的处理操作,并实现状态的循环转换。
以上是状态模式在Java中的几种实现方式,每种方式都有其独特的优点和适用场景,可以根据具体情况选择合适的方式来实现状态管理和转换。
策略模式
策略模式是一种行为型模式,用于定义一组算法,将每个算法都封装起来,并使它们可以相互替换。它使算法可以独立于使用它们的客户端而变化。
策略模式是一种常见的设计模式,它可以帮助我们实现对象行为的管理和动态选择,并使得系统更加灵活和可扩展。在Java中,我们可以使用以下几种方式来实现策略模式:
- 使用接口实现策略模式
在这种方式中,我们定义一个接口来表示策略,并在具体策略类中实现该接口。在上下文类中,我们维护一个当前策略对象,并在调用方法时使用该对象来执行相应的操作。以下是一个示例:
interface Strategy {
void execute();
}
class ConcreteStrategyA implements Strategy {
public void execute() {
System.out.println("Execute ConcreteStrategyA");
}
}
class ConcreteStrategyB implements Strategy {
public void execute() {
System.out.println("Execute ConcreteStrategyB");
}
}
class Context {
private Strategy strategy;
public Context(Strategy strategy) {
this.strategy = strategy;
}
public void setStrategy(Strategy strategy) {
this.strategy = strategy;
}
public void execute() {
strategy.execute();
}
}
public class StrategyDemo {
public static void main(String[] args) {
Strategy strategyA = new ConcreteStrategyA();
Context context = new Context(strategyA);
context.execute();
Strategy strategyB = new ConcreteStrategyB();
context.setStrategy(strategyB);
context.execute();
}
}
在上述示例中,我们定义了一个接口 Strategy
来表示策略,并实现了两个具体策略类 ConcreteStrategyA
和 ConcreteStrategyB
。在上下文类 Context
中,我们维护了一个当前策略对象,并在调用 execute()
方法时使用该对象来执行相应的操作。在 main
方法中,我们首先创建了一个具体策略对象和一个上下文对象,并设置初始策略为 ConcreteStrategyA
。通过调用 execute()
方法,我们可以根据当前策略执行相应的操作,并实现策略的动态选择。
- 使用抽象类实现策略模式
在这种方式中,我们定义一个抽象类来表示策略,并在具体策略类中继承该抽象类并实现其抽象方法。在上下文类中,我们维护一个当前策略对象,并在调用方法时使用该对象来执行相应的操作。以下是一个示例:
abstract class AbstractStrategy {
abstract void execute();
}
class ConcreteStrategyA extends AbstractStrategy {
public void execute() {
System.out.println("Execute ConcreteStrategyA");
}
}
class ConcreteStrategyB extends AbstractStrategy {
public void execute() {
System.out.println("Execute ConcreteStrategyB");
}
}
class Context {
private AbstractStrategy strategy;
public Context(AbstractStrategy strategy) {
this.strategy = strategy;
}
public void setStrategy(AbstractStrategy strategy) {
this.strategy = strategy;
}
public void execute() {
strategy.execute();
}
}
public class StrategyDemo {
public static void main(String[] args) {
AbstractStrategy strategyA = new ConcreteStrategyA();
Context context = new Context(strategyA);
context.execute();
AbstractStrategy strategyB = new ConcreteStrategyB();
context.setStrategy(strategyB);
context.execute();
}
}
在上述示例中,我们定义了一个抽象类 AbstractStrategy
来表示策略,并在具体策略类中继承该抽象类并实现其抽象方法。在上下文类 Context
中,我们维护了一个当前策略对象,并在调用 execute()
方法时使用该对象来执行相应的操作。在 main
方法中,我们首先创建了一个具体策略对象和一个上下文对象,并设置初始策略为 ConcreteStrategyA
。通过调用 execute()
方法,我们可以根据当前策略执行相应的操作,并实现策略的动态选择。
- 使用Lambda表达式实现策略模式
在Java 8及以上版本中,我们可以使用Lambda表达式来实现策略模式。在这种方式中,我们定义一个函数式接口来表示策略,并使用Lambda表达式来创建具体策略对象。在上下文类中,我们维护一个当前策略对象,并在调用方法时使用Lambda表达式来执行相应的操作。以下是一个示例:
interface Strategy {
void execute();
}
class Context {
private Strategy strategy;
public Context(Strategy strategy) {
this.strategy = strategy;
}
public void setStrategy(Strategy strategy) {
this.strategy = strategy;
}
public void execute() {
strategy.execute();
}
}
public class StrategyDemo {
public static void main(String[] args) {
Strategy strategyA = () -> System.out.println("Execute ConcreteStrategyA");
Context context = new Context(strategyA);
context.execute();
Strategy strategyB = () -> System.out.println("Execute ConcreteStrategyB");
context.setStrategy(strategyB);
context.execute();
}
}
在上述示例中,我们定义了一个函数式接口 Strategy
来表示策略,并使用Lambda表达式来创建具体策略对象。在上下文类 Context
中,我们维护了一个当前策略对象,并在调用 execute()
方法时使用Lambda表达式来执行相应的操作。在 main
方法中,我们首先创建了一个Lambda表达式作为具体策略对象,并创建了一个上下文对象,并设置初始策略为该Lambda表达式。通过调用 execute()
方法,我们可以根据当前策略执行相应的操作,并实现策略的动态选择。
以上是策略模式在Java中的几种实现方式,每种方式都有其独特的优点和适用场景,可以根据具体情况选择合适的方式来实现策略管理和动态选择。
模板方法模式
模板方法模式是一种行为型模式,用于定义一个算法的骨架,并将一些步骤延迟到子类中实现。它使子类可以在不改变算法结构的情况下重新定义算法中的某些步骤。
在Java中,模板方法模式是一种常见的设计模式,它定义了一个操作中的算法框架,而将一些步骤延迟到子类中实现。以下是几种实现模板方法模式的方式:
- 使用抽象类实现模板方法模式
在这种方式中,我们定义一个抽象类来表示模板方法,并在该抽象类中实现算法框架,将一些步骤延迟到具体子类中实现。以下是一个示例:
abstract class AbstractClass {
public void templateMethod() {
operation1();
operation2();
operation3();
}
protected abstract void operation1();
protected abstract void operation2();
protected abstract void operation3();
}
class ConcreteClassA extends AbstractClass {
protected void operation1() {
System.out.println("ConcreteClassA operation1");
}
protected void operation2() {
System.out.println("ConcreteClassA operation2");
}
protected void operation3() {
System.out.println("ConcreteClassA operation3");
}
}
class ConcreteClassB extends AbstractClass {
protected void operation1() {
System.out.println("ConcreteClassB operation1");
}
protected void operation2() {
System.out.println("ConcreteClassB operation2");
}
protected void operation3() {
System.out.println("ConcreteClassB operation3");
}
}
public class TemplateMethodDemo {
public static void main(String[] args) {
AbstractClass abstractClass = new ConcreteClassA();
abstractClass.templateMethod();
abstractClass = new ConcreteClassB();
abstractClass.templateMethod();
}
}
在上述示例中,我们定义了一个抽象类 AbstractClass
来表示模板方法,并在该抽象类中实现算法框架。具体子类 ConcreteClassA
和 ConcreteClassB
继承 AbstractClass
并实现抽象方法来延迟一些步骤的实现。在 main
方法中,我们创建了具体子类的对象,并调用模板方法 templateMethod()
来执行算法框架。通过子类的不同实现,我们可以实现算法框架的具体差异。
- 使用接口实现模板方法模式
在这种方式中,我们定义一个接口来表示模板方法,并在该接口中实现算法框架,将一些步骤延迟到具体实现类中实现。以下是一个示例:
interface Template {
void templateMethod();
}
class ConcreteTemplateA implements Template {
public void templateMethod() {
operation1();
operation2();
operation3();
}
private void operation1() {
System.out.println("ConcreteTemplateA operation1");
}
private void operation2() {
System.out.println("ConcreteTemplateA operation2");
}
private void operation3() {
System.out.println("ConcreteTemplateA operation3");
}
}
class ConcreteTemplateB implements Template {
public void templateMethod() {
operation1();
operation2();
operation3();
}
private void operation1() {
System.out.println("ConcreteTemplateB operation1");
}
private void operation2() {
System.out.println("ConcreteTemplateB operation2");
}
private void operation3() {
System.out.println("ConcreteTemplateB operation3");
}
}
public class TemplateMethodDemo {
public static void main(String[] args) {
Template template = new ConcreteTemplateA();
template.templateMethod();
template = new ConcreteTemplateB();
template.templateMethod();
}
}
在上述示例中,我们定义了一个接口 Template
来表示模板方法,并在该接口中实现算法框架。具体实现类 ConcreteTemplateA
和 ConcreteTemplateB
实现 Template
接口并实现模板方法。在 main
方法中,我们创建了具体实现类的对象,并调用模板方法 templateMethod()
来执行算法框架。通过实现类的不同实现,我们可以实现算法框架的具体差异。
- 使用Lambda表达式实现模板方法模式
在Java 8中,我们可以使用Lambda表达式实现模板方法模式。我们可以定义一个函数式接口来表示模板方法,在该函数式接口中实现算法框架,并使用Lambda表达式来延迟一些步骤的实现。以下是一个示例:
interface Template {
void templateMethod();
}
public class TemplateMethodDemo {
public static void main(String[] args) {
Template template = () -> {
operation1();
operation2();
operation3();
};
template.templateMethod();
}
private static void operation1() {
System.out.println("operation1");
}
private static void operation2() {
System.out.println("operation2");
}
private static void operation3() {
System.out.println("operation3");
}
}
在上述示例中,我们定义了一个函数式接口 Template
来表示模板方法,并使用Lambda表达式来实现算法框架。在 main
方法中,我们创建了一个Lambda表达式作为模板方法,并调用 templateMethod()
方法来执行算法框架。通过Lambda表达式的不同实现,我们可以实现算法框架的具体差异。
以上是几种在Java中实现模板方法模式的方式,每种方式都有其独特的优点和适用场景,可以根据实际需求来选择合适的方式。
访问者模式
访问者模式是一种行为型模式,用于将算法与其所操作的对象分离。它定义了一组操作,这些操作可以应用于同一组对象,并使这些操作可以独立于对象的类。
在Java中,访问者模式是一种常见的设计模式,它定义了一种算法,将其封装在一个对象结构中,并允许在不改变该结构的前提下定义新的操作。以下是几种实现访问者模式的方式,以及相应的示例:
- 使用抽象类实现访问者模式
在这种方式中,我们定义一个抽象访问者类来表示访问者,并在该类中定义访问不同元素的抽象方法。具体访问者类继承抽象访问者类,并实现抽象方法来定义不同的操作。元素类维护一个访问者对象,并调用访问者对象的相应方法来执行操作。以下是一个示例:
abstract class Visitor {
public abstract void visit(ElementA element);
public abstract void visit(ElementB element);
}
class ConcreteVisitorA extends Visitor {
public void visit(ElementA element) {
System.out.println("ConcreteVisitorA visit ElementA");
}
public void visit(ElementB element) {
System.out.println("ConcreteVisitorA visit ElementB");
}
}
class ConcreteVisitorB extends Visitor {
public void visit(ElementA element) {
System.out.println("ConcreteVisitorB visit ElementA");
}
public void visit(ElementB element) {
System.out.println("ConcreteVisitorB visit ElementB");
}
}
interface Element {
void accept(Visitor visitor);
}
class ElementA implements Element {
public void accept(Visitor visitor) {
visitor.visit(this);
}
}
class ElementB implements Element {
public void accept(Visitor visitor) {
visitor.visit(this);
}
}
public class VisitorDemo {
public static void main(String[] args) {
Element elementA = new ElementA();
Element elementB = new ElementB();
Visitor visitorA = new ConcreteVisitorA();
Visitor visitorB = new ConcreteVisitorB();
elementA.accept(visitorA);
elementB.accept(visitorA);
elementA.accept(visitorB);
elementB.accept(visitorB);
}
}
在上述示例中,我们定义了一个抽象访问者类 Visitor
来表示访问者,并在该类中定义访问不同元素的抽象方法。具体访问者类 ConcreteVisitorA
和 ConcreteVisitorB
继承 Visitor
类并实现抽象方法来定义不同的操作。元素类 ElementA
和 ElementB
实现 Element
接口来表示元素,并维护一个访问者对象,并调用访问者对象的相应方法来执行操作。在 main
方法中,我们创建了访问者对象和元素对象,并调用 accept
方法来执行相应的操作。
- 使用Lambda表达式实现访问者模式
在这种方式中,我们使用Lambda表达式来表示访问者,并将Lambda表达式作为参数传递给元素对象的 accept
方法。以下是一个示例:
interface Element {
void accept(Consumer<Element> visitor);
}
class ElementA implements Element {
public void accept(Consumer<Element> visitor) {
visitor.accept(this);
}
}
class ElementB implements Element {
public void accept(Consumer<Element> visitor) {
visitor.accept(this);
}
}
public class VisitorDemo {
public static void main(String[] args) {
Element elementA = new ElementA();
Element elementB = new ElementB();
Consumer<ElementA> visitorA = (element) -> System.out.println("VisitorA visit ElementA");
Consumer<ElementB> visitorB = (element) -> System.out.println("VisitorB visit ElementB");
elementA.accept(visitorA);
elementB.accept(visitorB);
}
}
在上述示例中,我们定义了一个接口 Element
来表示元素,并在该接口中定义一个 accept
方法,该方法接受一个 Consumer
对象作为参数来表示访问者。具体元素类 ElementA
和 ElementB
实现 Element
接口来表示元素,并在 accept
方法中将访问者对象作为参数传递给 Consumer
对象。在 main
方法中,我们创建了访问者对象 visitorA
和 visitorB
,并调用元素对象的 accept
方法来执行相应的访问操作。
- 使用反射实现访问者模式
在这种方式中,我们使用Java反射机制来动态调用访问者对象的方法。具体来说,我们在元素类中定义一个 accept
方法,该方法接受一个访问者对象作为参数,并使用反射机制来调用访问者对象的相应方法。以下是一个示例:
interface Element {
void accept(Visitor visitor);
}
class ElementA implements Element {
public void accept(Visitor visitor) {
try {
Method method = visitor.getClass().getMethod("visit", ElementA.class);
method.invoke(visitor, this);
} catch (Exception e) {
e.printStackTrace();
}
}
}
class ElementB implements Element {
public void accept(Visitor visitor) {
try {
Method method = visitor.getClass().getMethod("visit", ElementB.class);
method.invoke(visitor, this);
} catch (Exception e) {
e.printStackTrace();
}
}
}
interface Visitor {
}
class ConcreteVisitorA implements Visitor {
public void visit(ElementA element) {
System.out.println("ConcreteVisitorA visit ElementA");
}
public void visit(ElementB element) {
System.out.println("ConcreteVisitorA visit ElementB");
}
}
class ConcreteVisitorB implements Visitor {
public void visit(ElementA element) {
System.out.println("ConcreteVisitorB visit ElementA");
}
public void visit(ElementB element) {
System.out.println("ConcreteVisitorB visit ElementB");
}
}
public class VisitorDemo {
public static void main(String[] args) {
Element elementA = new ElementA();
Element elementB = new ElementB();
Visitor visitorA = new ConcreteVisitorA();
Visitor visitorB = new ConcreteVisitorB();
elementA.accept(visitorA);
elementB.accept(visitorA);
elementA.accept(visitorB);
elementB.accept(visitorB);
}
}
在上述示例中,我们定义了一个接口 Element
来表示元素,并在该接口中定义一个 accept
方法,该方法接受一个访问者对象作为参数。具体元素类 ElementA
和 ElementB
实现 Element
接口来表示元素,并在 accept
方法中使用反射机制来动态调用访问者对象的相应方法。在 main
方法中,我们创建了访问者对象 visitorA
和 visitorB
,并调用元素对象的 accept
方法来执行相应的访问操作。
- 使用Java8中的接口默认方法实现访问者模式
在Java8中,我们可以使用接口默认方法来实现访问者模式。具体来说,我们在元素接口中定义一个默认方法 accept
,该方法接受一个访问者对象作为参数,并调用访问者对象的相应方法。访问者接口中定义不同元素的访问方法。具体访问者类实现访问者接口,并实现相应的访问方法来定义不同的操作。以下是一个示例:
interface Element {
default void accept(Visitor visitor) {
if (this instanceof ElementA) {
visitor.visit((ElementA) this);
} else if (this instanceof ElementB) {
visitor.visit((ElementB) this);
}
}
}
class ElementA implements Element {
}
class ElementB implements Element {
}
interface Visitor {
default void visit(ElementA element) {
System.out.println("Visitor visit ElementA");
}
default void visit(ElementB element) {
System.out.println("Visitor visit ElementB");
}
}
class ConcreteVisitorA implements Visitor {
public void visit(ElementA element) {
System.out.println("ConcreteVisitorA visit ElementA");
}
}
class ConcreteVisitorB implements Visitor {
public void visit(ElementB element) {
System.out.println("ConcreteVisitorB visit ElementB");
}
}
public class VisitorDemo {
public static void main(String[] args) {
Element elementA = new ElementA();
Element elementB = new ElementB();
Visitor visitorA = new ConcreteVisitorA();
Visitor visitorB = new ConcreteVisitorB();
elementA.accept(visitorA);
elementB.accept(visitorA);
elementA.accept(visitorB);
elementB.accept(visitorB);
}
}
在上述示例中,我们定义了一个接口 Element
来表示元素,并在该接口中定义一个默认方法 accept
,该方法接受一个访问者对象作为参数,并调用访问者对象的相应方法。具体元素类 ElementA
和 ElementB
实现 Element
接口来表示元素。在访问者接口中,我们定义了不同元素的访问方法,并提供默认实现。具体访问者类 ConcreteVisitorA
和 ConcreteVisitorB
实现 Visitor
接口,并实现相应的访问方法来定义不同的操作。在 main
方法中,我们创建了访问者对象 visitorA
和 visitorB
,并调用元素对象的 accept
方法来执行相应的访问操作。
- 使用Lambda表达式实现访问者模式
在Java8中,我们还可以使用Lambda表达式来实现访问者模式。具体来说,我们在元素接口中定义一个默认方法 accept
,该方法接受一个函数式接口作为参数,并调用该函数式接口的相应方法。具体元素类实现元素接口来表示元素,并在 accept
方法中使用Lambda表达式来执行相应的操作。以下是一个示例:
interface Element {
default void accept(Consumer<Element> visitor) {
visitor.accept(this);
}
}
class ElementA implements Element {
}
class ElementB implements Element {
}
interface Visitor extends Consumer<Element> {
}
class ConcreteVisitorA implements Visitor {
public void accept(Element element) {
if (element instanceof ElementA) {
visit((ElementA) element);
} else if (element instanceof ElementB) {
visit((ElementB) element);
}
}
public void visit(ElementA element) {
System.out.println("ConcreteVisitorA visit ElementA");
}
public void visit(ElementB element) {
System.out.println("ConcreteVisitorA visit ElementB");
}
}
class ConcreteVisitorB implements Visitor {
public void accept(Element element) {
if (element instanceof ElementA) {
visit((ElementA) element);
} else if (element instanceof ElementB) {
visit((ElementB) element);
}
}
public void visit(ElementA element) {
System.out.println("ConcreteVisitorB visit ElementA");
}
public void visit(ElementB element) {
System.out.println("ConcreteVisitorB visit ElementB");
}
}
public class VisitorDemo {
public static void main(String[] args) {
Element elementA = new ElementA();
Element elementB = new ElementB();
Visitor visitorA = new ConcreteVisitorA();
Visitor visitorB = new ConcreteVisitorB();
elementA.accept(visitorA);
elementB.accept(visitorA);
elementA.accept(visitorB);
elementB.accept(visitorB);
}
}
在上述示例中,我们定义了一个接口 Element
来表示元素,并在该接口中定义一个默认方法 accept
,该方法接受一个函数式接口 Consumer<Element>
作为参数,并调用该函数式接口的相应方法。具体元素类 ElementA
和 ElementB
实现 Element
接口来表示元素,并在 accept
方法中使用Lambda表达式来执行相应的操作。在访问者接口 Visitor
中,我们继承了函数式接口 Consumer<Element>
,并提供了默认实现。具体访问者类 ConcreteVisitorA
和 ConcreteVisitorB
实现 Visitor
接口,并实现相应的访问方法来定义不同的操作。在 main
方法中,我们创建了访问者对象 visitorA
和 visitorB
,并调用元素对象的 accept
方法来执行相应的访问操作。
以上是Java中常用的设计模式,它们可以帮助您更有效地编写代码并解决常见问题。在实际应用中,您可以根据需要选择适当的设计模式来提高代码的复用性和可维护性。