一,观察者模式
观察者模式(Observer Pattern)是一种设计模式,它定义了对象之间的一对多依赖关系,当一个对象状态发生改变时,所有依赖于它的对象都会得到通知并自动更新。这种模式主要用于实现分布式事件处理系统,也称为发布-订阅(Publish-Subscribe)模式。
观察者模式的主要角色包括:
-
Subject(主题):
- 也被称为Observable,它维护一组观察者(Observer)的列表,并提供添加、删除和通知观察者的接口。
-
Observer(观察者):
- 观察者需要实现一个更新接口,当主题状态变化时,这个接口会被调用。
-
ConcreteSubject(具体主题):
- 实现Subject接口的具体类,维护状态,当状态变化时,通知所有注册的观察者。
-
ConcreteObserver(具体观察者):
- 实现Observer接口的具体类,负责更新自己来反映主题的状态。
观察者模式的实现步骤通常如下:
- 定义Subject接口,包括注册、移除和通知观察者的方法。
- 创建Subject的具体类,实现注册、移除和通知观察者的方法。
- 定义Observer接口,包括一个更新方法。
- 创建Observer的具体类,实现更新方法。
- 在Subject中维护一个观察者列表,当状态改变时,遍历列表并调用每个观察者的更新方法。
// 观察者接口
interface Observer {
void update(String 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);
}
}
// 主题接口
interface Subject {
void registerObserver(Observer o);
void removeObserver(Observer o);
void notifyObservers();
}
// 具体主题
class ConcreteSubject implements Subject {
private List<Observer> observers = new ArrayList<>();
private String state;
public void registerObserver(Observer o) {
observers.add(o);
}
public void removeObserver(Observer o) {
observers.remove(o);
}
public void notifyObservers() {
for (Observer observer : observers) {
observer.update(state);
}
}
public void setState(String state) {
this.state = state;
notifyObservers();
}
public String getState() {
return state;
}
}
public class ObserverPatternDemo {
public static void main(String[] args) {
ConcreteSubject subject = new ConcreteSubject();
Observer observer1 = new ConcreteObserver("Observer 1");
Observer observer2 = new ConcreteObserver("Observer 2");
subject.registerObserver(observer1);
subject.registerObserver(observer2);
subject.setState("Hello World!");
}
}
在这个例子中,ConcreteSubject
类维护了一个状态,当状态改变时,它会通知所有注册的观察者。ConcreteObserver
类实现了Observer
接口,并在接收到更新时打印消息。
观察者模式的优点包括:
- 降低了对象之间的耦合度。
- 增加了程序的可维护性。
- 支持广播通信。
缺点包括:
- 当观察者非常多时,通知的开销可能会很大。
- 如果存在循环依赖,可能导致系统崩溃。
装饰者模式(Decorator Pattern)是一种设计模式,它允许向一个现有的对象添加新的功能,同时又不改变其结构。这种模式创建了一个装饰类,用来包装原有的类,并在保持原类方法签名完整性的前提下,提供了额外的功能。
装饰者模式的主要角色包括:
-
Component(组件):
- 定义了对象的接口,可以给这些对象动态地添加职责。
-
ConcreteComponent(具体组件):
- 定义了对象的一个具体实现。
-
Decorator(装饰者):
- 持有一个Component对象的引用,并实现与Component接口一致的接口,这样装饰者可以替代原有对象。
-
ConcreteDecorator(具体装饰者):
- 负责给Component对象添加职责。
二,装饰者模式
装饰者模式的实现步骤通常如下:
- 定义一个接口或抽象类,它规定了对象的原始功能。
- 创建一个实现该接口的具体类。
- 创建一个装饰者类,它也实现同样的接口,并持有一个该接口类型的引用。
- 在装饰者类中,可以在原有功能的基础上添加额外的功能。
- 创建具体的装饰者类,实现额外的功能。
下面是一个简单的装饰者模式的代码示例:
// 组件接口
interface Component {
void operate();
}
// 具体组件
class ConcreteComponent implements Component {
@Override
public void operate() {
System.out.println("Component operating.");
}
}
// 装饰者抽象类
abstract class Decorator implements Component {
protected Component component;
public Decorator(Component component) {
this.component = component;
}
@Override
public void operate() {
component.operate();
}
}
// 具体装饰者
class ConcreteDecoratorA extends Decorator {
public ConcreteDecoratorA(Component component) {
super(component);
}
@Override
public void operate() {
super.operate();
addBehavior();
}
private void addBehavior() {
System.out.println("ConcreteDecoratorA added behavior.");
}
}
class ConcreteDecoratorB extends Decorator {
public ConcreteDecoratorB(Component component) {
super(component);
}
@Override
public void operate() {
super.operate();
addBehavior();
}
private void addBehavior() {
System.out.println("ConcreteDecoratorB added behavior.");
}
}
public class DecoratorPatternDemo {
public static void main(String[] args) {
Component component = new ConcreteComponent();
component = new ConcreteDecoratorA(component);
component = new ConcreteDecoratorB(component);
component.operate();
}
}
在这个例子中,ConcreteComponent
实现了Component
接口。Decorator
是一个抽象类,它持有一个Component
类型的引用,并实现了Component
接口。ConcreteDecoratorA
和ConcreteDecoratorB
是具体的装饰者类,它们在调用原有功能的基础上添加了额外的行为。
装饰者模式的优点包括:
- 动态地给一个对象添加功能,而不需要改变其代码。
- 可以多个装饰者组合使用,提供灵活的扩展性。
- 符合开闭原则,即对扩展开放,对修改封闭。
缺点包括:
- 如果过度使用装饰者模式,可能会导致设计过于复杂,难以理解。
- 装饰者模式可能会引入许多小对象,增加内存的开销。
三,策略模式
策略模式(Strategy Pattern)是一种设计模式,它定义了一系列算法,并将每一个算法封装起来,使它们可以互换使用,算法的变化不会影响使用算法的客户。策略模式让算法独立于使用它的客户端,这使得算法可以独立于客户端变化。
策略模式的主要角色包括:
-
Strategy(策略接口):
- 定义了一个算法或行为的家族,通常是一个由一组相关算法构成的接口。
-
ConcreteStrategy(具体策略):
- 实现了策略接口的具体算法或行为。
-
Context(上下文环境):
- 接受客户请求,随后将请求委托给策略对象以执行算法。
策略模式的实现步骤通常如下:
- 定义一个策略接口,它规定了所有支持的算法的公共方法。
- 创建实现该接口的具体策略类。
- 创建上下文环境类,它包含策略接口类型的引用,并提供一个方法来设置策略。
- 客户端代码可以通过创建具体的策略对象,并将其设置到上下文环境中,来改变程序的行为。
下面是一个简单的策略模式的代码示例:
// 策略接口
interface Strategy {
void execute();
}
// 具体策略A
class ConcreteStrategyA implements Strategy {
@Override
public void execute() {
System.out.println("Executing ConcreteStrategyA");
}
}
// 具体策略B
class ConcreteStrategyB implements Strategy {
@Override
public void execute() {
System.out.println("Executing ConcreteStrategyB");
}
}
// 上下文环境
class Context {
private Strategy strategy;
public void setStrategy(Strategy strategy) {
this.strategy = strategy;
}
public void executeStrategy() {
strategy.execute();
}
}
public class StrategyPatternDemo {
public static void main(String[] args) {
Context context = new Context();
// 客户端代码可以改变策略
context.setStrategy(new ConcreteStrategyA());
context.executeStrategy();
context.setStrategy(new ConcreteStrategyB());
context.executeStrategy();
}
}
在这个例子中,Strategy
是一个策略接口,ConcreteStrategyA
和ConcreteStrategyB
是实现了该接口的具体策略类。Context
类持有一个Strategy
类型的引用,并提供了executeStrategy
方法来执行策略。
策略模式的优点包括:
- 算法可以独立于使用它们的客户端变化。
- 客户端代码可以动态地改变对象的行为。
- 可以很容易地增加新的策略,而不需要修改现有的代码。
缺点包括:
- 客户端必须了解所有策略之间的差异,以便能够正确地使用它们。
- 如果有大量的策略,可能会导致策略类的数量过多。
四,适配器模式
适配器模式(Adapter Pattern)是一种结构型设计模式,它允许不兼容的接口之间的协同工作,使得原本由于接口不兼容而不能一起工作的类可以一起工作。适配器模式通常用于将一个类的接口转换成客户端期望的另一个接口。
适配器模式的主要角色包括:
-
Target(目标接口):
- 这是客户端所期望的接口,它定义了客户端需要使用的方法。
-
Adaptee(被适配者):
- 这是已有的类,它有一些功能,但是我们想要使用它的接口与我们期望的接口不匹配。
-
Adapter(适配器):
- 适配器类实现了目标接口,并在内部持有一个被适配者的引用,它将目标接口转换为被适配者接口。
适配器模式有两种常见的形式:
-
类适配器模式:
- 适配器类继承自被适配者,并实现目标接口。
-
对象适配器模式:
- 适配器类实现目标接口,并在内部持有被适配者的实例。
下面是一个简单的适配器模式的代码示例:
类适配器模式
// 目标接口
interface Target {
void request();
}
// 被适配者
class Adaptee {
public void specificRequest() {
System.out.println("Adaptee: Specific request");
}
}
// 类适配器
class ClassAdapter extends Adaptee implements Target {
@Override
public void request() {
specificRequest();
}
}
public class ClassAdapterPatternDemo {
public static void main(String[] args) {
Target target = new ClassAdapter();
target.request();
}
}
对象适配器模式
// 目标接口
interface Target {
void request();
}
// 被适配者
class Adaptee {
public void specificRequest() {
System.out.println("Adaptee: Specific request");
}
}
// 对象适配器
class ObjectAdapter implements Target {
private Adaptee adaptee;
public ObjectAdapter(Adaptee adaptee) {
this.adaptee = adaptee;
}
@Override
public void request() {
adaptee.specificRequest();
}
}
public class ObjectAdapterPatternDemo {
public static void main(String[] args) {
Adaptee adaptee = new Adaptee();
Target target = new ObjectAdapter(adaptee);
target.request();
}
}
在这两个例子中,Target
是目标接口,Adaptee
是被适配者,ClassAdapter
和ObjectAdapter
是适配器。适配器使得原本不兼容的Adaptee
类能够以Target
接口的形式被使用。
适配器模式的优点包括:
- 允许接口不兼容的类一起工作。
- 提供了一种不修改原有代码的情况下使用它的途径。
- 提高了代码的复用性。
缺点包括:
- 可能会引入一些复杂性,特别是当适配器需要转换很多不兼容的方法时。
- 适配器可能会隐藏不兼容操作的复杂性,导致客户端代码错误地假设所有操作都是直接的。
五,代理模式
代理模式(Proxy Pattern)是一种结构型设计模式,它为其他对象提供一个代理对象以控制对这个对象的访问。代理模式在不直接访问实际对象的情况下,提供了对目标对象的间接访问。通过引入一个代理对象来间接操作实际对象,可以在不改变实际对象代码的前提下,增加额外的功能操作,如访问控制、延迟初始化、日志记录等。
代理模式的主要角色包括:
-
Subject(主题接口):
- 定义了真实主题和代理对象共有的接口,这样代理可以用来代替真实主题。
-
RealSubject(真实主题):
- 定义了代理所代表的真实对象,实现了主题接口,它包含了真实的业务逻辑。
-
Proxy(代理主题):
- 包含了对真实主题的引用,实现了与真实主题相同的接口,并在真实主题对象的方法调用前后进行额外处理。
-
Client(客户端):
- 维护了对代理主题的引用,并在需要时通过代理主题间接调用真实主题的方法。
代理模式有几种不同的形式:
-
远程代理(Remote Proxy):
- 为远程对象(如网络服务)提供局部代表。
-
虚拟代理(Virtual Proxy):
- 延迟创建开销较大的对象,直到真正需要时才创建。
-
保护代理(Protection Proxy):
- 控制对原始对象的访问,提供权限检查。
-
智能引用代理(Smart Reference Proxy):
- 在访问对象时执行额外的动作,如引用计数、加载持久对象到内存等。
下面是一个简单的代理模式的代码示例:
// 主题接口
interface Subject {
void request();
}
// 真实主题
class RealSubject implements Subject {
@Override
public void request() {
System.out.println("RealSubject: Handling request.");
}
}
// 代理主题
class Proxy implements Subject {
private RealSubject realSubject;
public Proxy() {
this.realSubject = null;
}
@Override
public void request() {
if (realSubject == null) {
realSubject = new RealSubject();
}
preRequest();
realSubject.request();
postRequest();
}
private void preRequest() {
System.out.println("Proxy: Logging the time of request.");
}
private void postRequest() {
System.out.println("Proxy: Logging the time of request completion.");
}
}
public class ProxyPatternDemo {
public static void main(String[] args) {
Subject proxy = new Proxy();
proxy.request();
}
}
在这个例子中,Subject
是主题接口,RealSubject
是真实主题,Proxy
是代理主题。客户端通过代理主题间接地访问真实主题的方法,代理主题可以在真实主题的方法调用前后添加额外的处理逻辑。
代理模式的优点包括:
- 控制对原始对象的访问,可以在访问前进行权限检查等操作。
- 可以在不修改原始对象的基础上,通过引入代理对象来扩展功能。
- 可以延迟对象的创建,减少系统资源的消耗。
缺点包括:
- 可能会引入一些性能开销,因为每次访问真实对象时都需要通过代理对象。
- 设计可能会变得更加复杂,尤其是当有多个代理和多个真实对象时。
六,命令模式
命令模式(Command Pattern)是一种行为型设计模式,它将请求封装为一个对象,从而允许用户使用不同的请求、队列或日志请求来参数化其他对象。命令模式也支持可撤销的操作。
命令模式的主要角色包括:
-
Command(命令接口):
- 定义命令的接口,声明执行操作的方法。
-
ConcreteCommand(具体命令):
- 实现命令接口,对应于具体的行为和接收者的绑定。
-
Client(客户端):
- 创建一个具体命令对象并设置它的接收者。
-
Invoker(调用者):
- 要求命令对象执行请求。
-
Receiver(接收者):
- 知道如何实施与执行一个请求相关的操作。
命令模式的实现步骤通常如下:
- 定义命令接口,通常包含一个执行操作的方法。
- 创建实现命令接口的具体命令类。
- 创建接收者类,它包含具体实施操作的方法。
- 创建调用者类,它持有命令对象的引用,并提供一个方法来执行命令。
- 客户端创建具体命令对象,并设置其接收者,然后客户端将命令对象传给调用者。
下面是一个简单的命令模式的代码示例:
// 命令接口
interface Command {
void execute();
}
// 接收者
class Light {
public void on() {
System.out.println("Light is on");
}
public void off() {
System.out.println("Light is off");
}
}
// 具体命令
class LightOnCommand implements Command {
private Light light;
public LightOnCommand(Light light) {
this.light = light;
}
@Override
public void execute() {
light.on();
}
}
class LightOffCommand implements Command {
private Light light;
public LightOffCommand(Light light) {
this.light = light;
}
@Override
public void execute() {
light.off();
}
}
// 调用者
class RemoteControl {
private Command command;
public void setCommand(Command command) {
this.command = command;
}
public void pressButton() {
command.execute();
}
}
public class CommandPatternDemo {
public static void main(String[] args) {
Light light = new Light();
Command lightOn = new LightOnCommand(light);
Command lightOff = new LightOffCommand(light);
RemoteControl control = new RemoteControl();
// 打开灯
control.setCommand(lightOn);
control.pressButton();
// 关闭灯
control.setCommand(lightOff);
control.pressButton();
}
}
在这个例子中,Command
是命令接口,Light
是接收者,LightOnCommand
和LightOffCommand
是具体命令,RemoteControl
是调用者。客户端通过调用者来间接执行命令,命令对象将调用接收者的方法。
命令模式的优点包括:
- 将发起操作的对象(调用者)和执行操作的对象(接收者)解耦。
- 可以较容易地设计一个命令队列或日志来记录请求。
- 可以支持撤销操作。
- 可以动态地新增命令,无需修改已有类。
缺点包括:
- 可能会有大量的具体命令类,如果系统中的命令很多,这可能会增加系统的复杂性。
七,组合模式
组合模式(Composite Pattern)是一种结构型设计模式,它允许你将对象组合成树状结构来表示部分-整体的层次结构。组合模式使得客户可以统一地对待单个对象和组合对象。
组合模式的主要角色包括:
-
Component(组件接口):
- 为叶子对象和组合对象声明统一的接口。
-
Leaf(叶子对象):
- 表示组合中的叶节点对象,没有子节点。
-
Composite(组合对象):
- 定义有子部件的那些部件的行为,存储子部件。
-
Client(客户端):
- 通过组件接口操纵组合对象的结构。
组合模式的实现步骤通常如下:
- 定义组件接口,声明管理子组件的方法,如增加子组件、移除子组件等。
- 创建叶子对象类,实现组件接口。
- 创建组合对象类,实现组件接口,并包含子组件的管理逻辑。
- 客户端通过组件接口来操作组合对象和叶子对象。
下面是一个简单的组合模式的代码示例:
// 组件接口
interface Component {
void operation();
void add(Component component);
void remove(Component component);
}
// 叶子对象
class Leaf implements Component {
@Override
public void operation() {
System.out.println("Leaf is working.");
}
@Override
public void add(Component component) {
throw new UnsupportedOperationException();
}
@Override
public void remove(Component component) {
throw new UnsupportedOperationException();
}
}
// 组合对象
class Composite implements Component {
private List<Component> children = new ArrayList<>();
@Override
public void operation() {
for (Component child : children) {
child.operation();
}
}
@Override
public void add(Component component) {
children.add(component);
}
@Override
public void remove(Component component) {
children.remove(component);
}
}
public class CompositePatternDemo {
public static void main(String[] args) {
Composite fileSystem = new Composite();
Component folder1 = new Composite();
Component folder2 = new Composite();
Component file1 = new Leaf();
Component file2 = new Leaf();
folder1.add(file1);
folder1.add(file2);
folder2.add(new Leaf());
folder2.add(new Leaf());
fileSystem.add(folder1);
fileSystem.add(folder2);
fileSystem.operation();
}
}
在这个例子中,Component
是组件接口,Leaf
是叶子对象,Composite
是组合对象。客户端通过组件接口来操作组合对象和叶子对象,可以统一地对待它们。
组合模式的优点包括:
- 客户端可以统一地对待组合结构和单个对象。
- 可以很容易地添加新的叶子对象和组合对象。
- 符合开闭原则,即对扩展开放,对修改封闭。
缺点包括:
- 设计可能变得更加复杂,尤其是当组合结构变得复杂时。
- 在删除组合对象时,需要确保子节点也被正确处理。
八,迭代器模式
迭代器模式(Iterator Pattern)是一种行为型设计模式,它提供一种方法来顺序访问一个聚合对象中的各个元素,而不暴露其内部的表示。迭代器模式让迭代本身成为一个独立的对象,这样可以在不同的迭代过程中使用不同的迭代策略。
迭代器模式的主要角色包括:
-
Iterator(迭代器接口):
- 定义访问和遍历元素的接口,通常包含
hasNext()
、next()
和remove()
等方法。
- 定义访问和遍历元素的接口,通常包含
-
ConcreteIterator(具体迭代器):
- 实现迭代器接口,保持追踪当前遍历的位置。
-
Aggregate(聚合接口):
- 定义创建相应迭代器对象的接口。
-
ConcreteAggregate(具体聚合):
- 实现创建相应迭代器的接口,返回一个能遍历该具体聚合对象的迭代器。
迭代器模式的实现步骤通常如下:
- 定义迭代器接口,声明遍历元素的方法。
- 创建具体迭代器类,实现迭代器接口,并维护遍历状态。
- 定义聚合接口,声明创建迭代器对象的方法。
- 创建具体聚合类,实现聚合接口,并提供一个方法返回一个具体迭代器的实例。
- 客户端使用具体聚合对象来创建一个迭代器对象,然后使用该迭代器对象来遍历聚合对象中的元素。
下面是一个简单的迭代器模式的代码示例:
import java.util.ArrayList;
import java.util.List;
// 聚合接口
interface Aggregate {
Iterator createIterator();
}
// 具体聚合
class ConcreteAggregate extends Aggregate {
private List<Object> items = new ArrayList<>();
@Override
public Iterator createIterator() {
return new ConcreteIterator(this);
}
public void add(Object item) {
items.add(item);
}
public Object get(int index) {
return items.get(index);
}
public int size() {
return items.size();
}
}
// 迭代器接口
interface Iterator {
boolean hasNext();
Object next();
}
// 具体迭代器
class ConcreteIterator implements Iterator {
private ConcreteAggregate aggregate;
private int index = 0;
private List<Object> items;
public ConcreteIterator(ConcreteAggregate aggregate) {
this.aggregate = aggregate;
this.items = new ArrayList<>(aggregate.items);
}
@Override
public boolean hasNext() {
return index < aggregate.size();
}
@Override
public Object next() {
if (hasNext()) {
return items.get(index++);
}
return null;
}
}
public class IteratorPatternDemo {
public static void main(String[] args) {
ConcreteAggregate aggregate = new ConcreteAggregate();
aggregate.add("Item 1");
aggregate.add("Item 2");
aggregate.add("Item 3");
Iterator iterator = aggregate.createIterator();
while (iterator.hasNext()) {
System.out.println(iterator.next());
}
}
}
在这个例子中,Aggregate
是聚合接口,ConcreteAggregate
是具体聚合,Iterator
是迭代器接口,ConcreteIterator
是具体迭代器。客户端通过具体聚合对象来创建一个迭代器对象,然后使用该迭代器对象来遍历聚合对象中的元素。
迭代器模式的优点包括:
- 访问一个聚合对象的内容而无需暴露其内部细节。
- 可以提供多种遍历方式。
- 支持对聚合的多种访问,例如反向迭代。
- 可以很容易地添加新的迭代器。
缺点包括:
- 需要为每个聚合类型编写专门的迭代器类,这可能会增加代码量。
- 客户端需要知道如何获取迭代器,这可能违反了封装原则。