设计模式的起源可以追溯到20世纪80年代,当时面向对象编程开始流行。在这个时期,一些软件开发者开始注意到他们在不同的项目中遇到了相同的问题,并且他们开始寻找可重用的解决方案。这些解决方案被称为设计模式。最早提出设计模式的人是Erich Gamma、Richard Helm、Ralph Johnson和John Vlissides,他们在1994年出版了一本名为《设计模式:可复用面向对象软件的基础》的书,这本书成为了设计模式领域的经典著作。自那时以来,设计模式已经成为软件开发中非常重要的概念,并且在不同的编程语言和开发框架中都得到了广泛的应用。
四位作者合称 GOF(四人帮,全拼 Gang of Four)。他们所提出的设计模式主要是基于以下的面向对象设计原则。
设计模式是常见的软件设计问题的可重用解决方案。它们提供了一种解决开发人员在设计软件应用程序时经常遇到的问题的方法。设计模式有几种类型,包括创建型、结构型和行为型模式。
设计模式是软件开发中非常有用的工具,可以提高代码的可重用性和可维护性,同时也可以提高开发人员的工作效率。
单例模式(Singleton Pattern)是 Java 中最简单的设计模式之一,有以下特点:
这种方式比较常用,但容易产生垃圾对象
优点:没有加锁,执行效率会提高。
缺点:类加载时就初始化,浪费内存。
public class Singleton {
private static Singleton instance = new Singleton();
private Singleton() {}
public static Singleton getInstance() {
return instance;
}
}
在懒汉式基础上加入双重检验锁,保证线程安全和性能。
public class Singleton {
private volatile static Singleton instance = null;
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;
}
}
使用枚举来实现单例模式,保证线程安全和防止反射攻击。
1)将已经有的class转换成枚举单例
PersonEnum.INSTANCE.getInstance()
@Data
public class Person {
private String name;
private int age;
}
public enum PersonEnum {
INSTANCE;
private Person instance;
private PersonEnum(){
instance = new Person();
}
public Person getInstance() {
return instance;
}
}
2)直接新建枚举类
PersonSingleton.INSTANCE
public enum PersonSingleton {
INSTANCE;
private String name;
public String getName() {
return name;
}
}
原型设计模式允许通过复制现有对象来创建新对象,而不是通过实例化类来创建新对象。
在需要创建大量相似对象时非常有用,它可以避免重复创建对象,从而提高性能,并且可以根据需要实现浅拷贝或深拷贝。
在Java中,原型模式的实现通常涉及到实现Cloneable接口和重写clone()方法。
public abstract class Shape implements Cloneable {
private String id;
protected String type;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
public abstract void draw();
@Override
public Object clone() {
Object clone = null;
try {
clone = super.clone();
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
return clone;
}
}
public class Circle extends Shape {
public Circle() {
type = "Circle";
}
@Override
public void draw() {
System.out.println("Inside Circle::draw() method.");
}
}
public class Square extends Shape {
public Square() {
type = "Square";
}
@Override
public void draw() {
System.out.println("Inside Square::draw() method.");
}
}
public class ShapeCache {
private static Map<String, Shape> shapeMap = new HashMap<>();
public static Shape getShape(String shapeId) {
Shape cachedShape = shapeMap.get(shapeId);
return (Shape) cachedShape.clone();
}
// For each shape run database query and create shape
// shapeMap.put(shapeKey, shape);
// for example, we are adding three shapes
public static void loadCache() {
Circle circle = new Circle();
circle.setId("1");
shapeMap.put(circle.getId(), circle);
Square square = new Square();
square.setId("2");
shapeMap.put(square.getId(), square);
}
}
public class PrototypePatternDemo {
public static void main(String[] args) {
ShapeCache.loadCache();
Shape clonedShape = ShapeCache.getShape("1");
System.out.println("Shape : " + clonedShape.getType());
Shape clonedShape2 = ShapeCache.getShape("2");
System.out.println("Shape : " + clonedShape2.getType());
}
}
在上面的代码中,Shape是一个抽象类,它实现了Cloneable接口并重写了clone()方法。Circle和Square是Shape的具体子类,它们实现了draw()方法。ShapeCache类是一个缓存,它存储了Shape对象的副本。PrototypePatternDemo类是一个演示类,它使用ShapeCache来获取Shape对象的副本。
在loadCache()方法中,我们创建了两个Shape对象的副本,并将它们存储在shapeMap中。在main()方法中,我们使用getShape()方法来获取Shape对象的副本,并输出它们的类型。由于我们使用了原型模式,所以我们可以通过复制现有对象来创建新对象,而无需实例化类。
通过一个工厂类来实现对象的创建,而无需直接暴露对象的创建逻辑给客户端。
简单工厂模式的优点在于客户端无需了解具体产品类的创建细节,只需通过工厂类来创建对象,并且工厂类可以根据客户端的需求来动态创建不同类型的对象。但是缺点也比较明显,如果需要创建的产品类数量较多,则工厂类的代码会变得很臃肿,不便于维护。
abstract class Animal {
public abstract void sound();
}
class Cat extends Animal {
@Override
public void sound() {
System.out.println("喵喵喵");
}
}
class Dog extends Animal {
@Override
public void sound() {
System.out.println("汪汪汪");
}
}
// 创建一个工厂类
class AnimalFactory {
// 定义一个静态方法,根据传入的参数创建具体的产品类对象
public static Animal createAnimal(String type) {
if (type.equalsIgnoreCase("dog")) {
return new Dog();
} else if (type.equalsIgnoreCase("cat")) {
return new Cat();
} else {
throw new IllegalArgumentException("Invalid animal type: " + type);
}
}
}
// 客户端代码
public class Main {
public static void main(String[] args) {
// 使用工厂类创建不同的 Animal 对象
Animal dog = AnimalFactory.createAnimal("dog");
dog.sound();
Animal cat = AnimalFactory.createAnimal("cat");
cat.sound();
}
}
通过定义一个创建对象的接口来创建对象,但将具体实现的决定留给子类来决定。
在抽象工厂模式中,接口是负责创建一个相关对象的工厂,不需要显式指定它们的类。每个生成的工厂都能按照工厂模式提供对象。
// 创建一个抽象产品类
abstract class Animal {
public abstract void sound();
}
class Cat extends Animal {
@Override
public void sound() {
System.out.println("喵喵喵");
}
}
// 创建具体产品类,继承自 Animal 类
class Dog extends Animal {
@Override
public void sound() {
System.out.println("汪汪汪");
}
}
abstract class AnimalFactory {
// 定义一个抽象方法,用于创建 Animal 对象
public abstract Animal createAnimal();
}
class CatFactory extends AnimalFactory {
@Override
public Animal createAnimal() {
return new Cat();
}
}
// 创建具体工厂类,实现创建 Animal 对象的接口
class DogFactory extends AnimalFactory {
@Override
public Animal createAnimal() {
return new Dog();
}
}
// 客户端代码
public class Main {
public static void main(String[] args) {
// 创建一个 Dog 对象
AnimalFactory dogFactory = new DogFactory();
Animal dog = dogFactory.createAnimal();
dog.sound();
// 创建一个 Cat 对象
AnimalFactory catFactory = new CatFactory();
Animal cat = catFactory.createAnimal();
cat.sound();
}
}
建造者模式是一种创建型设计模式,它允许您通过一步一步地构建复杂对象来创建不同类型的对象。它使用一个建造者类来封装对象的创建过程并将其分解为多个简单的步骤。这使得您可以通过更改这些步骤来创建不同类型的对象。
在这个示例中,我们创建了Car类作为我们想要构建的复杂对象。然后,我们创建了CarBuilder类,该类逐步构建Car对象,并最终返回它。最后,我们使用CarBuilder来构建Car对象。
public class Car {
private String make;
private String model;
private int year;
private String engine;
private int seats;
public Car(String make, String model, int year, String engine, int seats) {
this.make = make;
this.model = model;
this.year = year;
this.engine = engine;
this.seats = seats;
}
// ... getter setter ... //
}
public class CarBuilder {
private String make;
private String model;
private int year;
private String engine;
private int seats;
public CarBuilder setMake(String make) {
this.make = make;
return this;
}
public CarBuilder setModel(String model) {
this.model = model;
return this;
}
public CarBuilder setYear(int year) {
this.year = year;
return this;
}
public CarBuilder setEngine(String engine) {
this.engine = engine;
return this;
}
public CarBuilder setSeats(int seats) {
this.seats = seats;
return this;
}
public Car build() {
return new Car(make, model, year, engine, seats);
}
}
Java适配器模式是一种结构型设计模式,它允许不兼容的接口之间进行通信。适配器模式通过将一个类的接口转换为客户端所期望的另一个接口来实现这一点。这种模式可以在不修改现有代码的情况下重用现有类。
适配器模式可以帮助我们在不修改现有代码的情况下重用现有类,并且可以使不兼容的接口之间进行通信。
主要作用:适配器模式将一个类的接口转换成客户希望的另外一个接口,使得原本由于接口不兼容而不能一起工作的那些类可以一起工作。
在下面的示例中,我们有一个目标接口 Target ,一个源接口 Adaptee 和一个适配器类 Adapter 。适配器类实现了目标接口,并且将请求转发到源接口的特定请求方法。客户端代码创建一个适配器对象,并使用它来调用目标接口的方法。
// 源接口
public class Adaptee {
public void specificRequest() {
System.out.println("Adaptee's specific request");
}
}
public interface Target {
public void request();
}
// 适配器类
public class Adapter implements Target {
private Adaptee adaptee;
public Adapter(Adaptee adaptee) {
this.adaptee = adaptee;
}
public void request() {
adaptee.specificRequest();
}
}
// 客户端代码
public class Client {
public static void main(String[] args) {
Adaptee adaptee = new Adaptee();
Target target = new Adapter(adaptee);
target.request();
}
}
组合模式是一种结构型设计模式,它允许你将对象组合成树形结构以表示“部分-整体”的层次结构。这种模式使得客户端可以统一对待单个对象和对象组合。
在组合模式中,有两种基本类型的对象:叶节点和组合节点。叶节点表示树形结构中的单个对象,而组合节点则表示树形结构中的对象组合。组合节点可以包含其他组合节点和/或叶节点,形成一个递归的树形结构。
以下是一个使用Java实现组合模式的示例代码,其中我们使用一个抽象类Component来表示树形结构中的节点,包括叶节点和组合节点。组合节点包含子节点,可以通过add()和remove()方法来添加和删除子节点。叶节点没有子节点,但可以实现共同的操作方法。具体的组合节点继承自Component类,实现自己的操作方法。
public interface IComponent {
void display();
}
// Component.java
public abstract class Component implements IComponent {
protected String name;
public Component(String name) {
this.name = name;
}
public abstract void add(IComponent component);
public abstract void remove(IComponent component);
}
// Composite.java
public class Composite extends Component {
private List<IComponent> children = new ArrayList<>();
public Composite(String name) {
super(name);
}
@Override
public void add(IComponent component) {
children.add(component);
}
@Override
public void remove(IComponent component) {
children.remove(component);
}
@Override
public void display() {
System.out.println("Composite: " + name);
for (IComponent component : children) {
component.display();
}
}
}
// Leaf.java
public class Leaf implements IComponent {
private String name;
public Leaf(String name) {
this.name = name;
}
@Override
public void display() {
System.out.println("Leaf: " + name);
}
}
// Client.java
public class Client {
public static void main(String[] args) {
Component root = new Composite("root");
Component branch1 = new Composite("branch1");
Component branch2 = new Composite("branch2");
Component leaf1 = new Leaf("leaf1");
Component leaf2 = new Leaf("leaf2");
Component leaf3 = new Leaf("leaf3");
root.add(branch1);
root.add(branch2);
branch1.add(leaf1);
branch2.add(leaf2);
branch2.add(leaf3);
root.display();
}
}
装饰器模式是一种结构性设计模式,它允许您在不影响同一类的其他对象的行为的情况下,静态或动态地向单个对象添加行为。 当您想要在运行时添加或删除对象的功能时,或者当您想要减少创建不同行为组合所需的子类数量时,此模式非常有用。
在Java中,使用继承和组合的结合来实现装饰器模式。 具体来说,您需要创建一个基类或接口来定义对象的核心行为,然后创建一个或多个装饰器类来向对象添加附加行为。 每个装饰器类都具有对其装饰的对象的引用,并且它可以在委托给对象的原始行为之前或之后修改对象的行为。
装饰器模式适用于以下场景:
使用装饰器模式时需要注意以下几点:
public interface Pizza {
public String getDescription();
public double getCost();
}
// 具体组件
public class PlainPizza implements Pizza {
public String getDescription() {
return "薄饼";
}
public double getCost() {
return 4.00;
}
}
// 装饰器
public abstract class ToppingDecorator implements Pizza {
protected Pizza pizza;
public ToppingDecorator(Pizza pizza) {
this.pizza = pizza;
}
public String getDescription() {
return pizza.getDescription();
}
public double getCost() {
return pizza.getCost();
}
}
// 具体装饰器
public class Cheese extends ToppingDecorator {
public Cheese(Pizza pizza) {
super(pizza);
}
public String getDescription() {
return pizza.getDescription() + ",马苏里拉奶酪";
}
public double getCost() {
return pizza.getCost() + 0.50;
}
}
// 具体装饰器
public class Pepperoni extends ToppingDecorator {
public Pepperoni(Pizza pizza) {
super(pizza);
}
public String getDescription() {
return pizza.getDescription() + ",意大利辣香肠";
}
public double getCost() {
return pizza.getCost() + 1.00;
}
}
// 客户端代码
public class PizzaShop {
public static void main(String[] args) {
Pizza pizza = new PlainPizza();
pizza = new Cheese(pizza);
pizza = new Pepperoni(pizza);
System.out.println(pizza.getDescription());
System.out.println("成本:$" + pizza.getCost());
}
}
在此示例中,我们有一个 Pizza 接口,它定义了Pizza 的核心行为,包括其描述和成本。 然后我们有一个 PlainPizza 类,它实现了 Pizza 接口。
接下来,我们创建一个抽象的 ToppingDecorator 类,它实现 Pizza 接口并具有对其装饰的 Pizza 对象的引用。 这允许我们向 Pizza 对象添加附加行为而不修改原始对象。
最后,我们创建了两个具体的装饰器类 Cheese 和 Pepperoni ,它们向 Pizza 对象添加附加行为。 每个装饰器类修改 getDescription() 和 getCost() 方法以在委托给原始对象之前或之后添加自己的行为。
在客户端代码中,我们创建一个 PlainPizza 对象,然后用 Cheese 对象和 Pepperoni 对象装饰它。 然后打印出Pizza 的描述和成本以验证装饰器是否修改了原始对象的行为。
外观模式(Facade Pattern)是一种结构型设计模式,它提供了一个简单的接口来访问复杂系统中的子系统,从而隐藏了子系统的复杂性。外观模式属于对象型模式,它通过创建一个外观类,将客户端与子系统解耦,使得客户端只需要与外观类交互即可完成操作。
class CPU {
public void processData() {
System.out.println("正在处理数据...");
}
}
class Memory {
public void load() {
System.out.println("正在加载内存...");
}
}
class HardDrive {
public void readData() {
System.out.println("正在读取硬盘数据...");
}
}
// 外观类
class ComputerFacade {
private CPU cpu;
private Memory memory;
private HardDrive hardDrive;
public ComputerFacade() {
cpu = new CPU();
memory = new Memory();
hardDrive = new HardDrive();
}
public void start() {
System.out.println("启动计算机...");
cpu.processData();
memory.load();
hardDrive.readData();
System.out.println("计算机启动完毕!");
}
}
// 客户端代码
public class FacadePatternDemo {
public static void main(String[] args) {
ComputerFacade computer = new ComputerFacade();
computer.start();
}
}
在这个示例中,我们有三个子系统类: CPU , Memory 和 HardDrive 。每个类都执行系统的不同功能,例如处理数据,加载内存和读取硬盘数据。
然后,我们创建了一个 ComputerFacade 类,它封装了这三个子系统类,并提供了一个简单的 start() 方法,客户端可以使用该方法启动计算机。在 start() 方法中,我们按照正确的顺序调用每个子系统的方法,以确保计算机正确启动。
最后,在客户端代码中,我们创建了一个 ComputerFacade 对象,并使用 start() 方法启动计算机。由于外观类隐藏了系统的复杂性,客户端代码非常简单。
享元模式(Flyweight Pattern)是一种结构型设计模式,它通过共享对象来减少内存使用和对象创建的开销。享元模式属于对象型模式,它通过创建一个享元工厂来管理共享对象,并在需要时返回已经存在的对象,从而减少对象的创建和销毁次数。
interface Shape {
void draw();
}
// 具体享元类
class Circle implements Shape {
private String color;
private int x;
private int y;
private int radius;
public Circle(String color) {
this.color = color;
}
public void setX(int x) {
this.x = x;
}
public void setY(int y) {
this.y = y;
}
public void setRadius(int radius) {
this.radius = radius;
}
@Override
public void draw() {
System.out.println("画了一个" + color + "的圆,半径为" + radius + ",位置为(" + x + "," + y + ")");
}
}
// 享元工厂类
class ShapeFactory {
private static final Map<String, Shape> circleMap = new HashMap<>();
public static Shape getCircle(String color) {
Circle circle = (Circle) circleMap.get(color);
if (circle == null) {
circle = new Circle(color);
circleMap.put(color, circle);
System.out.println("创建了一个" + color + "的圆");
}
return circle;
}
}
// 客户端代码
public class FlyweightPatternDemo {
private static final String[] colors = { "红色", "绿色", "蓝色", "黄色", "黑色" };
public static void main(String[] args) {
for (int i = 0; i < 20; i++) {
Circle circle = (Circle) ShapeFactory.getCircle(getRandomColor());
circle.setX(getRandomX());
circle.setY(getRandomY());
circle.setRadius(100);
circle.draw();
}
}
private static String getRandomColor() {
return colors[(int) (Math.random() * colors.length)];
}
private static int getRandomX() {
return (int) (Math.random() * 100);
}
private static int getRandomY() {
return (int) (Math.random() * 100);
}
}
在这个示例中,我们有一个 Shape 接口,它定义了一个 draw() 方法,用于绘制图形。
然后,我们创建了一个具体的享元类 Circle ,它实现了 Shape 接口,并存储了圆的颜色、位置和半径等信息。
接下来,我们创建了一个享元工厂类 ShapeFactory ,它维护了一个 Map ,用于存储已经创建的圆对象。在客户端需要绘制圆时,我们可以通过 ShapeFactory 获取已经存在的圆对象,如果不存在,则创建一个新的圆对象,并将其存储在 Map 中。
最后,在客户端代码中,我们随机生成20个圆,每个圆的颜色、位置和半径都是随机的。通过 ShapeFactory 获取圆对象,并调用它的 draw() 方法来绘制图形。由于相同颜色的圆对象被共享,因此减少了内存使用和对象创建的开销。
代理模式是项目中常用的一种设计模式。提供了间接访问目标对象的一种方式;即通过代理对象访问目标对象。
这样做的好处是,可以在不改变原有目标对象的基础上,对目标对象增加额外的扩展功能。
代理模式又分为静态代理、jdk动态代理、cglib动态代理三种实现方式。
三种实现方式各有优点,以及适用的场景:
被代理对象与代理对象需要实现相同的接口或者是继承相同父类,因此要定义一个接口或抽象类。
/**代理接口*/
public interface IHello {
String hi(String key);
}
/**代理接口实现类*/
public class HelloImpl implements IHello {
@Override
public String hi(String key) {
String str = "hello:" + key;
System.out.println("HelloImpl! " + str);
return str;
}
}
/**静态代理类*/
public class HelloStaticProxy implements IHello {
private IHello hello;
public HelloStaticProxy(IHello hello) {
this.hello = hello;
}
@Override
public String hi(String key) {
System.out.println(">>> static proxy start");
String result = hello.hi(key);
System.out.println(">>> static proxy end");
return result;
}
}
/**测试*/
public class DemoTest {
public static void main(String[] args) {
IHello helloProxy = new HelloStaticProxy(new HelloImpl());
helloProxy.hi("world");
}
}
jdk动态代理是基于接口的一种代理方式,目标对象一定要实现接口。
原理是,利用反射机制,动态生成匿名类继承Proxy类并且实现了要代理的接口,由于java不支持多继承,所以JDK动态代理不能代理类
/**代理接口*/
public interface IHello {
String hi(String key);
}
/**代理接口实现类*/
public class HelloImpl implements IHello {
@Override
public String hi(String key) {
String str = "hello:" + key;
System.out.println("HelloImpl! " + str);
return str;
}
}
/**jdk动态代理类*/
public class JdkProxy implements InvocationHandler {
private Object target;
public JdkProxy(Object target) {
this.target = target;
}
/**
* 获取被代理接口实例对象
*
* @param
* @return
*/
public <T> T getProxy() {
return (T) Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), this);
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println(">>> JdkProxy start");
Object result = method.invoke(target, args);
System.out.println(">>> JdkProxy end");
return result;
}
}
/**测试*/
public class Demo2Test {
public static void main(String[] args) {
JdkProxy proxy = new JdkProxy(new HelloImpl());
IHello helloProxy = proxy.getProxy();
helloProxy.hi(" jdk proxy !");
}
}
目标对象可以不用实现接口,不能针对final类进行代理。
原理是,动态生成class继承目标对象。使用cglib必须引入对应的jar包
<dependency>
<groupId>cglibgroupId>
<artifactId>cglibartifactId>
<version>3.2.7version>
dependency>
/**目标类*/
public class HelloImpl {
public String hi(String key) {
String str = "hello:" + key;
System.out.println("HelloImpl! " + str);
return str;
}
}
/**cglib代理类*/
public class CglibProxy implements InvocationHandler {
private Object target;
/**
* 获取被代理接口实例对象
*/
public <T> T getProxy() {
//1创建增强器对象
Enhancer e = new Enhancer();
//2设置增强器的类加载器
e.setClassLoader(target.getClass().getClassLoader());
//3设置代理对象父类类型
e.setSuperclass(target.getClass());
//4设置回调函数
e.setCallback(this);
//5创建代理对象
return (T) e.create();
}
public CglibProxy(Object target) {
this.target = target;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println(">>> cglib start");
Object obj = method.invoke(target, args);
System.out.println(">>> cglib end");
return obj;
}
}
/**测试*/
public class Demo3Test {
public static void main(String[] args) {
HelloImpl hello = new HelloImpl();
CglibProxy cglibProxy = new CglibProxy(hello);
HelloImpl proxy = cglibProxy.getProxy();
proxy.hi(" cglib ");
}
}
桥接模式是一种将抽象化和实现化解耦的设计模式。它使用了封装、聚合以及继承等基本技术,将两个独立变化的维度通过抽象化的方式进行桥接,从而降低了它们之间的耦合度,使得系统更加灵活。
下面是 Java 中桥接模式实现的示例代码:
// 首先,我们定义一个 Color 接口,它表示颜色:
public interface Color {
void applyColor();
}
// 然后,我们定义一个 Shape 抽象类,它包含了一个 Color 对象:
public abstract class Shape {
protected Color color;
public Shape(Color color) {
this.color = color;
}
public abstract void applyColor();
}
// 接下来,我们定义两个实现了 Color 接口的具体类:
public class Red implements Color {
@Override
public void applyColor() {
System.out.println("Applying red color");
}
}
public class Blue implements Color {
@Override
public void applyColor() {
System.out.println("Applying blue color");
}
}
// 最后,我们定义两个实现了 Shape 抽象类的具体类:
public class Circle extends Shape {
public Circle(Color color) {
super(color);
}
@Override
public void applyColor() {
System.out.print("Circle applying color: ");
color.applyColor();
}
}
public class Square extends Shape {
public Square(Color color) {
super(color);
}
@Override
public void applyColor() {
System.out.print("Square applying color: ");
color.applyColor();
}
}
// 现在,我们可以使用这些类来创建出对应的对象并调用它们的方法:
public class Test {
public static void main(String[] args) {
Color blue = new Blue();
Shape square = new Square(new Red());
Shape circle = new Circle(blue);
square.applyColor();
circle.applyColor();
}
}
输出结果如下:
Square applying color: Applying red color
Circle applying color: Applying blue color
这是一个简单的桥接模式实现,它允许我们在运行时动态地改变 Shape 类的颜色而不用影响到 Shape 子类,同时也允许我们增加新的颜色和形状类而无需改变其它现有的类。
责任链模式是一种行为设计模式,它允许将请求沿着处理链进行传递,直到有一个处理程序处理它为止。在Java中实现责任链模式通常需要以下几个步骤:
public interface Handler {
Handler setNextHandler(Handler nextHandler);
void handleRequest(Request request);
}
// 创建抽象处理器类
public abstract class AbstractHandler implements Handler {
private Handler nextHandler;
public Handler setNextHandler(Handler nextHandler) {
this.nextHandler = nextHandler;
return this.nextHandler;
}
public Handler getNextHandler() {
return nextHandler;
}
}
// 创建具体的处理器类
public class ConcreteHandler1 extends AbstractHandler {
public void handleRequest(Request request) {
if (request.getType().equals("Type1")) {
System.out.println("ConcreteHandler1 handles request " + request);
} else {
getNextHandler().handleRequest(request);
}
}
}
public class ConcreteHandler2 extends AbstractHandler {
public void handleRequest(Request request) {
if (request.getType().equals("Type2")) {
System.out.println("ConcreteHandler2 handles request " + request);
} else {
getNextHandler().handleRequest(request);
}
}
}
public class ConcreteHandler3 extends AbstractHandler {
public void handleRequest(Request request) {
if (request.getType().equals("Type3")) {
System.out.println("ConcreteHandler3 handles request " + request);
} else {
getNextHandler().handleRequest(request);
}
}
}
// 创建请求类
public class Request {
private String type;
public Request(String type) {
this.type = type;
}
public String getType() {
return type;
}
public String toString() {
return "Request [type=" + type + "]";
}
}
// 客户端代码
public class Client {
public static void main(String[] args) {
Handler handler1 = new ConcreteHandler1();
Handler handler2 = new ConcreteHandler2();
Handler handler3 = new ConcreteHandler3();
handler1.setNextHandler(handler2)
.setNextHandler(handler3);
handler1.handleRequest(new Request("Type1"));
handler1.handleRequest(new Request("Type2"));
handler1.handleRequest(new Request("Type3"));
}
}
输入结果:
ConcreteHandler1 handles request Request [type=Type1]
ConcreteHandler2 handles request Request [type=Type2]
ConcreteHandler3 handles request Request [type=Type3]
以上代码演示了如何创建一个处理器链,并将请求沿着链传递,直到有一个处理程序处理它为止。在这个例子中,ConcreteHandler1、ConcreteHandler2和ConcreteHandler3都是具体的处理器类,它们继承自AbstractHandler类,并实现handleRequest方法。客户端代码创建了一个处理器链,并将请求发送到链的第一个处理器。当请求到达处理器时,它会检查请求类型是否与处理器可以处理的类型匹配。如果是,处理器将处理请求。否则,它将请求传递给链中的下一个处理器,直到有一个处理程序处理它为止。
命令模式是一种行为设计模式,它允许将请求封装为一个对象,从而使不同的请求可以使用不同的参数进行参数化,队列或日志请求,以及支持可撤销的操作。在Java中,命令模式的实现通常涉及一个命令接口和一个或多个具体命令类,这些类实现了命令接口,并在其execute()方法中定义了实际的命令逻辑。此外,命令模式还可能涉及一个调用者类,该类将一个或多个命令对象与接收者对象关联起来,并在需要时调用它们的execute()方法。命令模式是一种非常灵活和可扩展的模式,可以用于许多不同的应用程序场景。
interface Command {
void execute(String[] args);
}
// 定义具体命令
class CreateFileCommand implements Command {
public void execute(String[] args) {
// 根据给定的名称和内容创建文件的代码
System.out.println("创建文件 : " + String.join(", ", args));
}
}
class DeleteFileCommand implements Command {
public void execute(String[] args) {
// 根据给定的名称删除文件的代码
System.out.println("删除文件 : "+String.join(",",args) );
}
}
// 定义命令执行者
class CommandExecutor {
private Map<String, Command> commands = new HashMap<>();
public CommandExecutor() {
// 将具体命令与命令名称关联起来
commands.put("create", new CreateFileCommand());
commands.put("delete", new DeleteFileCommand());
}
public void executeCommand(String commandName, String[] args) {
// 查找对应的命令并执行
Command command = commands.get(commandName);
if (command != null) {
command.execute(args);
} else {
System.out.println("Unknown command: " + commandName);
}
}
}
// 使用命令执行者执行命令
public class Main {
public static void main(String[] args) {
CommandExecutor executor = new CommandExecutor();
executor.executeCommand("create", new String[]{"file.txt", "Hello World!"});
executor.executeCommand("delete", new String[]{"file.txt"});
executor.executeCommand("unknown", new String[]{});
}
}
执行输出:
创建文件 : file.txt, Hello World!
删除文件 : file.txt
Unknown command: unknown
Java解释器模式是一种行为设计模式,它定义了一种语言和该语言的解释器,使得可以使用该语言来表达一些特定的操作。该模式适用于需要解释一些特定语言的场景,例如编译器、表达式计算器等。
在Java中,可以使用抽象语法树(AST)来表示语言表达式,并使用解释器来执行这些表达式。解释器模式通常包括以下几个组件:
以下是一个简单的Java解释器模式示例代码:
interface Expression {
int interpret(Context context);
}
// 终结符表达式
class NumberExpression implements Expression {
private int value;
public NumberExpression(int value) {
this.value = value;
}
public int interpret(Context context) {
return value;
}
}
// 非终结符表达式
class AddExpression implements Expression {
private Expression left;
private Expression right;
public AddExpression(Expression left, Expression right) {
this.left = left;
this.right = right;
}
public int interpret(Context context) {
return left.interpret(context) + right.interpret(context);
}
}
// 上下文
class Context {
private Map<String, Integer> variables = new HashMap<>();
public void setVariable(String name, int value) {
variables.put(name, value);
}
public int getVariable(String name) {
return variables.get(name);
}
}
// 解释器
class Interpreter {
private Expression expression;
public Interpreter(Expression expression) {
this.expression = expression;
}
public int interpret(Context context) {
return expression.interpret(context);
}
}
// 使用解释器执行表达式
public class Main {
public static void main(String[] args) {
// 创建上下文
Context context = new Context();
context.setVariable("a", 10);
context.setVariable("b", 20);
// 创建表达式
Expression expression = new AddExpression(
new NumberExpression(context.getVariable("a")),
new NumberExpression(context.getVariable("b"))
);
// 创建解释器并执行表达式
Interpreter interpreter = new Interpreter(expression);
int result = interpreter.interpret(context);
System.out.println("Result: " + result);
}
}
在上面的示例代码中,我们定义了两个终结符表达式(NumberExpression)和一个非终结符表达式(AddExpression),用于表示加法操作。我们还定义了一个上下文(Context),用于存储变量和函数,以及一个解释器(Interpreter),用于执行表达式。最后,我们使用解释器执行了一个简单的加法表达式,并打印出了结果。
Java迭代器模式是一种行为设计模式,它提供了一种访问集合对象元素的方法,而不需要暴露该对象的内部表示。该模式适用于需要遍历集合对象的场景,例如数组、列表、树等。
下面是一个简单的Java迭代器模式示例代码,使用数组存储,实现了一个数组迭代器:
interface Iterator<T> {
boolean hasNext();
T next();
}
// 具体迭代器实现类
class ArrayIterator<T> implements Iterator<T> {
private T[] array;
private int currentIndex;
public ArrayIterator(T[] array) {
this.array = array;
this.currentIndex = 0;
}
public boolean hasNext() {
return currentIndex < array.length;
}
public T next() {
if (!hasNext()) {
throw new NoSuchElementException();
}
T element = array[currentIndex];
currentIndex++;
return element;
}
}
// 使用迭代器遍历数组
public class Main {
public static void main(String[] args) {
Integer[] array = {1, 2, 3, 4, 5};
Iterator<Integer> iterator = new ArrayIterator<>(array);
while (iterator.hasNext()) {
System.out.println(iterator.next());
}
}
}
在上面的示例代码中,我们定义了抽象迭代器接口(Iterator),用于表示迭代器对象。我们还定义了具体迭代器实现类(ArrayIterator),用于实现数组迭代器。最后,我们使用迭代器遍历了一个整型数组,并打印出了每个元素的值。
Java观察者模式是一种行为设计模式,它定义了一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖它的对象都会得到通知并自动更新。该模式适用于需要在对象间建立动态的、松散耦合的关系的场景,例如事件处理等。
观察者模式适用于以下场景:
总之,观察者模式适用于需要在对象间建立动态的、松散耦合的关系的场景,例如事件处理、GUI编程、消息队列等。
下面是一个简单的Java观察者模式示例代码,实现了一个气象站,当气象数据发生改变时,会通知所有的观察者对象:
import java.util.ArrayList;
import java.util.List;
// 抽象主题接口
interface Subject {
void registerObserver(Observer observer);
void removeObserver(Observer observer);
void notifyObservers();
}
// 具体观察者实现类
class Display implements Observer {
private float temperature;
private float humidity;
private float pressure;
private String name;
@Override
public String name() {
return this.name;
}
public Display(String name){
this.name = name;
}
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("Temperature: " + temperature);
System.out.println("Humidity: " + humidity);
System.out.println("Pressure: " + pressure);
}
}
// 抽象观察者接口
interface Observer {
void update(float temperature, float humidity, float pressure);
String name();
}
// 具体观察者实现类
class Display implements Observer {
private float temperature;
private float humidity;
private float pressure;
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("Temperature: " + temperature);
System.out.println("Humidity: " + humidity);
System.out.println("Pressure: " + pressure);
}
}
// 使用观察者模式实现气象站
public class Main {
public static void main(String[] args) {
WeatherStation weatherStation = new WeatherStation();
Display display1 = new Display();
Display display2 = new Display();
weatherStation.registerObserver(display1);
weatherStation.registerObserver(display2);
weatherStation.setMeasurements(25.0f, 60.0f, 1013.0f);
weatherStation.removeObserver(display2);
weatherStation.setMeasurements(26.0f, 65.0f, 1012.0f);
}
}
执行输入结果:
>> 通知所有观察者 <<
------观察者:01-----------
Temperature: 25.0
Humidity: 60.0
Pressure: 1013.0
------观察者:02-----------
Temperature: 25.0
Humidity: 60.0
Pressure: 1013.0
>> 通知所有观察者 <<
------观察者:01-----------
Temperature: 26.0
Humidity: 65.0
Pressure: 1012.0
在上面的示例代码中,我们定义了抽象主题接口(Subject)和抽象观察者接口(Observer),用于表示主题和观察者对象。我们还定义了具体主题实现类(WeatherStation)和具体观察者实现类(Display),用于实现气象站和显示器对象。最后,我们使用观察者模式实现了一个气象站,当气象数据发生改变时,会通知所有的观察者对象,并更新显示器的数据。
Java提供的一种内置的观察者模式实现。它使用了Java中的Observable类和Observer接口来实现观察者模式。
Observable类是一个抽象类,它表示一个可观察的对象,具有添加、删除和通知观察者的方法。当Observable对象的状态发生改变时,会调用它的notifyObservers()方法,通知所有的观察者对象,并更新它们的状态。Observable类还提供了setChanged()方法和clearChanged()方法,用于标记Observable对象的状态是否发生了改变。
Observer接口表示观察者对象,具有更新状态的方法update()。当Observable对象的状态发生改变时,会调用观察者对象的update()方法,传递更新的数据。
import java.util.Observable;
import java.util.Observer;
// 具体主题类
class WeatherStation extends Observable {
private float temperature;
private float humidity;
private float pressure;
public void setMeasurements(float temperature, float humidity, float pressure) {
this.temperature = temperature;
this.humidity = humidity;
this.pressure = pressure;
setChanged();
notifyObservers();
}
public float getTemperature() {
return temperature;
}
public float getHumidity() {
return humidity;
}
public float getPressure() {
return pressure;
}
}
// 具体观察者类
class Display implements Observer {
private float temperature;
private float humidity;
private float pressure;
public void update(Observable o, Object arg) {
if (o instanceof WeatherStation) {
WeatherStation weatherStation = (WeatherStation) o;
this.temperature = weatherStation.getTemperature();
this.humidity = weatherStation.getHumidity();
this.pressure = weatherStation.getPressure();
display();
}
}
public void display() {
System.out.println("Temperature: " + temperature);
System.out.println("Humidity: " + humidity);
System.out.println("Pressure: " + pressure);
}
}
// 使用JDK自带观察者模式实现气象站
public class Main {
public static void main(String[] args) {
WeatherStation weatherStation = new WeatherStation();
Display display1 = new Display();
Display display2 = new Display();
weatherStation.addObserver(display1);
weatherStation.addObserver(display2);
weatherStation.setMeasurements(25.0f, 60.0f, 1013.0f);
weatherStation.deleteObserver(display2);
weatherStation.setMeasurements(26.0f, 65.0f, 1012.0f);
}
}
在上面的示例代码中,我们使用了Observable类和Observer接口来实现气象站和显示器对象。当气象数据发生改变时,Observable对象会调用notifyObservers()方法,通知所有的观察者对象,并更新它们的状态。观察者对象实现Observer接口的update()方法,用于更新自己的状态。
Java状态模式是一种行为型设计模式,它允许对象在内部状态改变时改变它的行为。状态模式将状态封装成独立的类,并将请求委托给当前状态对象,从而实现状态的切换和状态行为的变化。
使用状态模式的场景包括:
注意事项:
下面是一个使用Java状态模式实现的示例代码:
interface State {
void handle();
}
// 具体状态类1
class ConcreteState1 implements State {
public void handle() {
System.out.println("ConcreteState1 is handling.");
}
}
// 具体状态类2
class ConcreteState2 implements State {
public void handle() {
System.out.println("ConcreteState2 is handling.");
}
}
// 环境类
class Context {
private State state;
public void setState(State state) {
this.state = state;
}
public void request() {
state.handle();
}
}
// 使用状态模式实现的客户端代码
public class Main {
public static void main(String[] args) {
Context context = new Context();
State state1 = new ConcreteState1();
State state2 = new ConcreteState2();
context.setState(state1);
context.request();
context.setState(state2);
context.request();
}
}
在上面的示例代码中,我们定义了一个状态接口State和两个具体状态类ConcreteState1和ConcreteState2。我们还定义了一个环境类Context,它包含一个状态对象,并定义了一个请求方法request(),用于调用当前状态对象的handle()方法。在客户端代码中,我们创建了一个Context对象,并设置它的状态为ConcreteState1,然后调用request()方法,输出"ConcreteState1 is handling.“。接着,我们将Context的状态设置为ConcreteState2,并再次调用request()方法,输出"ConcreteState2 is handling.”。
通过使用状态模式,我们可以将状态和行为分离,使得对象的行为可以随着状态的改变而改变,从而实现更加灵活的设计。
Java模板模式是一种行为设计模式,它定义了一个操作中的程序骨架,将一些步骤延迟到子类中实现。这使得子类可以在不改变程序结构的情况下重新定义程序中的某些步骤。
在Java模板模式中,有两种类型的方法:抽象方法和具体方法。抽象方法由子类实现,而具体方法由父类实现。模板方法是由具体方法和抽象方法组成的,它定义了程序的骨架,而具体方法则实现了算法的部分步骤。
Java模板模式适用于以下场景:
总之,Java模板模式适用于那些需要在程序中定义骨架,并且在子类中实现具体步骤的情况。它可以提高代码的复用性和可维护性,同时也可以使代码更加灵活和可扩展。
下面是一个简单的Java模板模式示例代码:
abstract class Game {
abstract void initialize();
abstract void startPlay();
abstract void endPlay();
// 模板方法
public final void play() {
// 初始化游戏
initialize();
// 开始游戏
startPlay();
// 结束游戏
endPlay();
}
}
class Cricket extends Game {
@Override
void endPlay() {
System.out.println("Cricket Game Finished!");
}
@Override
void initialize() {
System.out.println("Cricket Game Initialized! Start playing.");
}
@Override
void startPlay() {
System.out.println("Cricket Game Started. Enjoy the game!");
}
}
class Football extends Game {
@Override
void endPlay() {
System.out.println("Football Game Finished!");
}
@Override
void initialize() {
System.out.println("Football Game Initialized! Start playing.");
}
@Override
void startPlay() {
System.out.println("Football Game Started. Enjoy the game!");
}
}
public class TemplatePatternDemo {
public static void main(String[] args) {
Game game = new Cricket();
game.play();
System.out.println();
game = new Football();
game.play();
}
}
在上面的代码中,Game类是一个抽象类,定义了一个play()方法作为模板方法。Cricket和Football类是具体的实现类,它们实现了抽象类中定义的抽象方法。在main()方法中,我们创建了一个Cricket对象和一个Football对象,并调用它们的play()方法。这样我们就可以在不改变算法结构的情况下重新定义算法中的某些步骤。
Java中介者模式是一种行为设计模式,它允许对象之间通过中介者对象进行通信,从而避免对象之间的直接耦合。中介者模式将对象之间的复杂关系转化为中介者和对象之间的简单关系,从而提高了系统的灵活性和可维护性。
在Java中介者模式中,中介者对象负责协调对象之间的通信,它通常包含一些公共方法,用于处理对象之间的交互。对象之间的通信通过中介者对象进行,从而避免了对象之间的直接耦合。
下面是一个简单的Java中介者模式示例代码:
// Mediator接口定义了send()方法,用于处理对象之间的交互。
interface Mediator {
void send(String message, Colleague colleague);
}
// Colleague抽象类表示对象,它包含一个Mediator对象,用于处理对象之间的通信。
abstract class Colleague {
protected Mediator mediator;
public Colleague(Mediator mediator) {
this.mediator = mediator;
}
public abstract void receive(String message);
public abstract void send(String message);
}
// ConcreteColleague1和ConcreteColleague2是具体的对象实现类,它们实现了Colleague抽象类中的方法。
class ConcreteColleague1 extends Colleague {
public ConcreteColleague1(Mediator mediator) {
super(mediator);
}
@Override
public void receive(String message) {
System.out.println("Colleague1 received message: " + message);
}
@Override
public void send(String message) {
System.out.println("Colleague1 sends message: " + message);
mediator.send(message, this);
}
}
class ConcreteColleague2 extends Colleague {
public ConcreteColleague2(Mediator mediator) {
super(mediator);
}
@Override
public void receive(String message) {
System.out.println("Colleague2 received message: " + message);
}
@Override
public void send(String message) {
System.out.println("Colleague2 sends message: " + message);
mediator.send(message, this);
}
}
// ConcreteMediator是具体的中介者实现类,它负责协调对象之间的通信。
class ConcreteMediator implements Mediator {
private ConcreteColleague1 colleague1;
private ConcreteColleague2 colleague2;
public void setColleague1(ConcreteColleague1 colleague1) {
this.colleague1 = colleague1;
}
public void setColleague2(ConcreteColleague2 colleague2) {
this.colleague2 = colleague2;
}
@Override
public void send(String message, Colleague colleague) {
if (colleague == colleague1) {
colleague2.receive(message);
} else {
colleague1.receive(message);
}
}
}
public class MediatorPatternDemo {
public static void main(String[] args) {
ConcreteMediator mediator = new ConcreteMediator();
ConcreteColleague1 colleague1 = new ConcreteColleague1(mediator);
ConcreteColleague2 colleague2 = new ConcreteColleague2(mediator);
mediator.setColleague1(colleague1);
mediator.setColleague2(colleague2);
colleague1.send("Hello, Colleague2.");
colleague2.send("Hello, Colleague1.");
}
}
在上面的代码中,Mediator接口定义了send()方法,用于处理对象之间的交互。Colleague抽象类表示对象,它包含一个Mediator对象,用于处理对象之间的通信。ConcreteColleague1和ConcreteColleague2是具体的对象实现类,它们实现了Colleague抽象类中的方法。ConcreteMediator是具体的中介者实现类,它负责协调对象之间的通信。
在main()方法中,我们创建了一个ConcreteMediator对象和两个ConcreteColleague对象,并调用它们的send()方法进行通信。通过中介者对象进行通信,避免了对象之间的直接耦合。
Java备忘录模式是一种行为设计模式,它允许在不破坏封装性的情况下捕获和恢复对象的内部状态。备忘录模式通常用于需要撤销操作或恢复先前状态的情况下。该模式包括三个主要组件:原始对象、备忘录对象和负责管理备忘录对象的对象。
下面是一个简单的Java备忘录模式示例代码:
// Originator类表示原始对象,它包含需要保存的状态。
class Originator {
private String state;
public void setState(String state) {
this.state = state;
}
public String getState() {
return state;
}
// createMemento()方法创建备忘录对象,并将当前状态保存到备忘录对象中。
public Memento createMemento() {
return new Memento(state);
}
// restore()方法用于从备忘录对象中恢复先前的状态。
public void restore(Memento memento) {
state = memento.getState();
}
}
// Memento类表示备忘录对象,它包含需要保存的状态。
class Memento {
private String state;
public Memento(String state) {
this.state = state;
}
public String getState() {
return state;
}
}
// Caretaker类负责管理备忘录对象,它包含一个Memento对象。
class Caretaker {
private Memento memento;
public void setMemento(Memento memento) {
this.memento = memento;
}
public Memento getMemento() {
return memento;
}
}
public class MementoPatternDemo {
public static void main(String[] args) {
Originator originator = new Originator();
Caretaker caretaker = new Caretaker();
// 保存原始对象的状态到备忘录对象中
originator.setState("State 1");
caretaker.setMemento(originator.createMemento());
// 修改原始对象的状态
originator.setState("State 2");
// 从备忘录对象中恢复先前的状态
originator.restore(caretaker.getMemento());
System.out.println("Current state: " + originator.getState());
}
}
在上面的代码中,Originator类表示原始对象,它包含需要保存的状态。createMemento()方法创建备忘录对象,并将当前状态保存到备忘录对象中。restore()方法用于从备忘录对象中恢复先前的状态。
Memento类表示备忘录对象,它包含需要保存的状态。
Caretaker类负责管理备忘录对象,它包含一个Memento对象。
在main()方法中,我们创建了一个Originator对象和一个Caretaker对象,并调用它们的方法进行状态保存和恢复。通过备忘录模式,我们可以在不破坏封装性的情况下捕获和恢复对象的内部状态。
Java访问者模式是一种行为型设计模式,它允许你在不修改对象结构的前提下定义新的操作。访问者模式将对象结构和操作分离开来,使得操作可以独立地应用于对象结构中的元素。在访问者模式中,有两个主要角色:访问者和元素。访问者定义了对元素进行操作的方法,而元素则提供了接受访问者的方法。
下面是一个访问者模式的示例代码,其中我们将实现一个简单的计算器,它可以对表达式进行计算。我们将使用访问者模式来遍历表达式树,并对每个节点执行相应的操作。
访问者模式适用于以下场景:
常见的使用访问者模式的场景包括:编译器的语法分析、XML文档解析、静态分析器、模型验证器、模型转换器等。
interface Expression {
void accept(Visitor visitor);
}
class NumberExpression implements Expression {
private int value;
public NumberExpression(int value) {
this.value = value;
}
public int getValue() {
return value;
}
public void accept(Visitor visitor) {
visitor.visit(this);
}
}
// 定义具体的元素类:加法表达式
class AdditionExpression implements Expression {
private Expression left;
private Expression right;
public AdditionExpression(Expression left, Expression right) {
this.left = left;
this.right = right;
}
public Expression getLeft() {
return left;
}
public Expression getRight() {
return right;
}
public void accept(Visitor visitor) {
visitor.visit(this);
}
}
interface Visitor {
void visit(NumberExpression expression);
void visit(AdditionExpression expression);
}
// 定义具体的访问者类:打印访问者
class PrinterVisitor implements Visitor {
public void visit(NumberExpression expression) {
System.out.print(expression.getValue());
}
public void visit(AdditionExpression expression) {
System.out.print("(");
expression.getLeft().accept(this);
System.out.print("+");
expression.getRight().accept(this);
System.out.print(")");
}
}
class CalculatorVisitor implements Visitor {
private int result;
public void visit(NumberExpression expression) {
result = expression.getValue();
}
public void visit(AdditionExpression expression) {
expression.getLeft().accept(this);
int leftValue = result;
expression.getRight().accept(this);
int rightValue = result;
result = leftValue + rightValue;
}
public int getResult() {
return result;
}
}
public class Client {
public static void main(String[] args) {
// 构建表达式树:1 + (2 + 3)
Expression expression = new AdditionExpression(
new NumberExpression(1),
new AdditionExpression(
new NumberExpression(2),
new NumberExpression(3)
)
);
// 计算表达式的值
CalculatorVisitor calculator = new CalculatorVisitor();
expression.accept(calculator);
System.out.println("Result: " + calculator.getResult());
// 打印表达式的字符串表示
PrinterVisitor printer = new PrinterVisitor();
expression.accept(printer);
}
}
输出结果:
Result: 6
(1+(2+3))
上面的例子中,我们定了一个表达式接口Expression,并提供了两个表达式实现类数字表达式NumberExpression和加法表达式AdditionExpression,定义了一个访问者接口Visitor,以及两个具体访问者CalculatorVisitor、PrinterVisitor,两个访问者接收表达式对象,并在访问者中对表达式实现具体操作,分别是表达式运算以及表达式打印。上面例子没有改变具体的表达式类,且定义了新的操作。
策略模式是一种行为型设计模式,它允许您定义一系列算法,将每个算法封装起来,并使它们可以互换使用。这种模式使得算法可以独立于使用它们的客户端而变化。
在Java中,策略模式通常由一个接口和多个实现该接口的类组成。客户端将使用该接口来调用算法,而不是直接调用实现类。这样,客户端就可以在运行时选择不同的算法实现,而不需要修改代码。
下面的例子展示了如何使用策略模式来实现一个简单的支付系统。我们定义了一个接口 PaymentStrategy ,并创建了多个实现该接口的类,每个类代表一种不同的支付方式。客户端可以根据需要选择使用哪种支付方式。
interface PaymentStrategy {
void pay(double amount);
}
class CreditCardPayment implements PaymentStrategy {
private String cardNumber;
private String cvv;
private String expiryDate;
public CreditCardPayment(String cardNumber, String cvv, String expiryDate) {
this.cardNumber = cardNumber;
this.cvv = cvv;
this.expiryDate = expiryDate;
}
public void pay(double amount) {
System.out.println("Paying " + amount + " using credit card.");
}
}
class PayPalPayment implements PaymentStrategy {
private String email;
private String password;
public PayPalPayment(String email, String password) {
this.email = email;
this.password = password;
}
public void pay(double amount) {
System.out.println("Paying " + amount + " using PayPal.");
}
}
class CashPayment implements PaymentStrategy {
public void pay(double amount) {
System.out.println("Paying " + amount + " using cash.");
}
}
class PaymentProcessor {
private PaymentStrategy strategy;
public PaymentProcessor(PaymentStrategy strategy) {
this.strategy = strategy;
}
public void setStrategy(PaymentStrategy strategy) {
this.strategy = strategy;
}
public void processPayment(double amount) {
strategy.pay(amount);
}
}
public class PaymentSystem {
public static void main(String[] args) {
PaymentProcessor processor = new PaymentProcessor(new CreditCardPayment("1234 5678 9012 3456", "123", "12/23"));
processor.processPayment(100.0);
processor.setStrategy(new PayPalPayment("[email protected]", "password"));
processor.processPayment(50.0);
processor.setStrategy(new CashPayment());
processor.processPayment(25.0);
}
}
执行输出:
Paying 100.0 using credit card.
Paying 50.0 using PayPal.
Paying 25.0 using cash.
在上面的示例中, PaymentStrategy 接口定义了一种支付方式,并包含一个 pay 方法,该方法接受一个金额参数。我们创建了三个实现该接口的类,分别代表信用卡支付、PayPal支付和现金支付。 PaymentProcessor 类接受一个 PaymentStrategy 实例作为参数,并使用它来执行支付操作。在 main 方法中,我们创建了一个 PaymentProcessor 实例,并使用不同的支付方式来进行支付。
下面再介绍两种常用的设计模式
Java过滤器设计模式是一种常用的设计模式,用于在请求到达目标对象之前或之后,对请求进行处理或过滤。该模式可以用于实现不同的功能,如验证、授权、日志记录、压缩等,将不同的操作当作过滤链中的一个过滤器。
下面是一个简单的Java过滤器设计模式的示例代码:
public interface Filter {
public void doFilter(String request);
}
// 定义授权过滤器
public class AuthenticationFilter implements Filter {
public void doFilter(String request) {
System.out.println("Authenticating request: " + request);
}
}
// 定义日志过滤器
public class LoggingFilter implements Filter {
public void doFilter(String request) {
System.out.println("Logging request: " + request);
}
}
// 定义过滤器链
public class FilterChain {
private List<Filter> filters = new ArrayList<Filter>();
private int index = 0;
public void addFilter(Filter filter) {
filters.add(filter);
}
public void doFilter(String request) {
if (index == filters.size()) {
return;
}
Filter filter = filters.get(index);
index++;
filter.doFilter(request);
doFilter(request);
}
}
public class Main {
public static void main(String[] args) {
FilterChain chain = new FilterChain();
chain.addFilter(new AuthenticationFilter());
chain.addFilter(new LoggingFilter());
chain.doFilter("request");
}
}
上述示例代码展示了Java过滤器设计模式的基本实现方法。通过定义不同的过滤器类来链接它们,可以实现不同的功能。
Java空对象模式是一种行为设计模式,它允许我们在不返回null的情况下提供默认行为。这种模式通常用于需要处理null对象的情况下,以避免NullPointerException异常。该模式包括两个主要组件:抽象类和具体类。
interface User {
String getName();
boolean hasAccess();
}
// 定义一个具体类,表示一个真实的用户
class RealUser implements User {
private String name;
private boolean hasAccess;
public RealUser(String name, boolean hasAccess) {
this.name = name;
this.hasAccess = hasAccess;
}
public String getName() {
return name;
}
public boolean hasAccess() {
return hasAccess;
}
}
// 定义一个空对象,表示一个空的用户
class NullUser implements User {
public String getName() {
return "Guest";
}
public boolean hasAccess() {
return false;
}
}
// 定义一个工厂类,用于创建用户
class UserFactory {
// 根据名称和权限创建一个用户
public static User getUser(String name, boolean hasAccess) {
if (name == null) {
return new NullUser();
}
return new RealUser(name, hasAccess);
}
}
public class NullObjectPatternDemo {
public static void main(String[] args) {
User user1 = UserFactory.getUser("Alice", true);
User user2 = UserFactory.getUser(null, false);
System.out.println("User 1: " + user1.getName() + ", has access: " + user1.hasAccess());
System.out.println("User 2: " + user2.getName() + ", has access: " + user2.hasAccess());
}
}
在上面的代码中,我们定义了一个接口User,它表示一个用户,并包含两个方法:getName()和hasAccess()。接着,我们定义了一个具体类RealUser,它表示一个真实的用户,并实现了User接口的两个方法。我们还定义了一个空对象NullUser,它表示一个空的用户,并实现了User接口的两个方法。最后,我们定义了一个工厂类UserFactory,用于创建用户。如果传入的名称为null,则返回一个空对象NullUser,否则返回一个真实的用户RealUser。
在main()方法中,我们使用UserFactory创建了两个用户user1和user2,并打印它们的名称和是否有权限。由于user2的名称为null,因此它将返回一个空对象NullUser,并打印出"Guest"字符串和false布尔值。通过空对象模式,我们可以在不返回null的情况下提供默认行为,避免NullPointerException异常。