1、请解释什么是设计模式,并列举出你熟悉的几种设计模式。
设计模式是软件开发中经常出现的问题的通用、可重用的解决方案。它不是可以直接转化为代码的完成设计,而是描述在各种不同情况下如何解决问题的模板。我熟悉的设计模式包括单例模式、工厂模式、观察者模式、装饰器模式、策略模式。
2、请解释单例模式,并给出Java实现示例。
单例模式是一种创建型的设计模式,它保证一个类只有一个实例,并提供一个全局访问点。Java中的实现通常使用双重检查锁定机制来保证线程安全。
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;
}
}
3、请解释工厂模式和抽象工厂模式,他们之间有什么区别?
工厂模式是一种创建型设计模式,提供了一种创建对象的最佳方式。在工厂模式中,我们在创建对象时不会对客户端暴露创建逻辑,而是通过一个共同的接口来指向新创建的对象。抽象工厂模式是工厂模式的升级版本,可以创建多个工厂。
4、请解释观察者模式,并给出一个Java的实现示例。
观察者模式是一种行为设计模式,它定义了对象之间的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都会得到通知并被自动更新。Java中的实现可以使用java.util.Observable类和java.util.Observer接口。
import java.util.ArrayList;
import java.util.List;
// 定义观察者接口
interface Observer {
void update(String message);
}
// 定义被观察者接口
interface Observable {
void registerObserver(Observer observer);
void removeObserver(Observer observer);
void notifyObservers();
}
// 具体的被观察者
class ConcreteObservable implements Observable {
private List<Observer> observers;
private String message;
public ConcreteObservable() {
this.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() {
for (Observer observer : observers) {
observer.update(message);
}
}
public void setMessage(String message) {
this.message = message;
notifyObservers();
}
}
// 具体的观察者
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);
}
}
// 测试代码
public class ObserverPatternDemo {
public static void main(String[] args) {
ConcreteObservable observable = new ConcreteObservable();
observable.registerObserver(new ConcreteObserver("Observer 1"));
observable.registerObserver(new ConcreteObserver("Observer 2"));
observable.setMessage("Hello, Observer Pattern!");
}
}
在这个示例中,ConcreteObservable
是被观察者,ConcreteObserver
是观察者。当ConcreteObservable
的状态(这里是message
)发生改变时,所有注册的观察者都会收到通知。
5、请解释装饰器模式,并给出一个Java示例。
装饰器模式是一种设计模式,允许在运行时动态地将行为添加到对象中,而不改变其类的代码。这种类型的设计模式属于结构型设计模式,它提供了一种替代继承的方式来扩展对象的功能。
// 定义组件接口
interface Component {
void operation();
}
// 具体组件
class ConcreteComponent implements Component {
@Override
public void operation() {
System.out.println("ConcreteComponent operation");
}
}
// 抽象装饰类
abstract class Decorator implements Component {
protected Component component;
public Decorator(Component component) {
this.component = component;
}
@Override
public void operation() {
component.operation();
}
}
// 具体装饰类
class ConcreteDecorator extends Decorator {
public ConcreteDecorator(Component component) {
super(component);
}
@Override
public void operation() {
super.operation();
addedFunction();
}
public void addedFunction() {
System.out.println("ConcreteDecorator added function");
}
}
// 测试代码
public class DecoratorPatternDemo {
public static void main(String[] args) {
Component component = new ConcreteComponent();
Component decorator = new ConcreteDecorator(component);
decorator.operation();
}
}
在这个示例中,ConcreteComponent
是具体的组件,ConcreteDecorator
是具体的装饰器。装饰器ConcreteDecorator
在不改变ConcreteComponent
的情况下,为其添加了新的功能addedFunction
。
6、请解释策略模式,并给出一个Java的实现示例。
策略模式是一种行为设计模式,它定义了一系列的算法,并将每一个算法封装起来,使他们可以互相替换。策略模式让算法的变化独立于使用算法的客户。
// 定义策略接口
interface Strategy {
void execute();
}
// 具体策略A
class ConcreteStrategyA implements Strategy {
@Override
public void execute() {
System.out.println("Strategy A");
}
}
// 具体策略B
class ConcreteStrategyB implements Strategy {
@Override
public void execute() {
System.out.println("Strategy B");
}
}
// 环境类
class Context {
private Strategy strategy;
public Context(Strategy strategy) {
this.strategy = strategy;
}
public void executeStrategy() {
strategy.execute();
}
}
// 测试代码
public class StrategyPatternDemo {
public static void main(String[] args) {
Context contextA = new Context(new ConcreteStrategyA());
contextA.executeStrategy();
Context contextB = new Context(new ConcreteStrategyB());
contextB.executeStrategy();
}
}
在这个示例中,ConcreteStrategyA和ConcreteStrategyB是具体的策略,Context是环境类。环境类Context在运行时可以选择使用那种策略,从而实现了策略的动态切换。
7、请解释什么是依赖倒置原则,它在设计模式中的应用是什么?
依赖倒置原则是面向对象的五个基本原则之一,它要求依赖于抽象而不是依赖于具体。在设计模式中,例如工厂模式、策略模式等都是用了依赖倒置原则。
8、请解释什么是适配器模式,它解决了什么问题?请给出一个Java示例。
适配器模式是一种结构型设计模式,它通过把一个类的接口变换成客户端锁期待的另一种接口,可以帮助我们使得原本由于接口不兼容而不能一起工作的类能够一起工作。
// 目标接口
interface Target {
void request();
}
// 需要适配的类
class Adaptee {
public void specificRequest() {
System.out.println("Adaptee specific request");
}
}
// 适配器类
class Adapter implements Target {
private Adaptee adaptee;
public Adapter(Adaptee adaptee) {
this.adaptee = adaptee;
}
@Override
public void request() {
adaptee.specificRequest();
}
}
// 测试代码
public class AdapterPatternDemo {
public static void main(String[] args) {
Adaptee adaptee = new Adaptee();
Target target = new Adapter(adaptee);
target.request();
}
}
在这个示例中,Adaptee是需要适配的类,它有一个specificRequest方法;Target是目标接口,它有一个request方法;Adapter是适配器类,它实现了Target接口,并在request方法中调用了Adaptee的specificRequest方法。这样,客户端就可以通过Target接口来使用Adaptee的specificRequest方法了。
9、请解释什么是命令模式,他在什么场景下会被使用?请给出一个Java的实现示例。
命令模式是一种行为设计模式,它将一个请求封装为一个对象,从而使你可以用不同的请求对客户进行参数化,对请求排队或记录请求日志,以及支持可撤销的操作。
命令模式常用于以下场景:
- 需要将操作请求者与操作执行者解耦,使得调用者不直接调用接受者。
- 需要在不同的时间指定、排列和执行请求。
- 需要支持撤销操作。
// 命令接口
interface Command {
void execute();
}
// 具体命令
class ConcreteCommand implements Command {
private Receiver receiver;
public ConcreteCommand(Receiver receiver) {
this.receiver = receiver;
}
@Override
public void execute() {
receiver.action();
}
}
// 接收者
class Receiver {
public void action() {
System.out.println("Receiver action");
}
}
// 请求者
class Invoker {
private Command command;
public Invoker(Command command) {
this.command = command;
}
public void call() {
command.execute();
}
}
// 测试代码
public class CommandPatternDemo {
public static void main(String[] args) {
Receiver receiver = new Receiver();
Command command = new ConcreteCommand(receiver);
Invoker invoker = new Invoker(command);
invoker.call();
}
}
在这个示例中,Receiver是接收者,ConcreteCommand是具体的命令,他在execute方法中调用了Receiver的action方法;Invoker是请求者,它通过调用Command的execute方法来发出请求。这样,Invoker就可以通过Command接口来间接调用Receiver的action方法了。
10、请解释什么是代理模式,他和装饰器模式有什么区别?请给出一个Java示例。
代理模式是一种设计模式,提供了对目标对象另外的访问方式;即通过代理对象访问目标对象。这样可以在不修改原目标对象的情况下,提供而外的操作,比如添加访问权限,请求处理等。
代理模式和装饰器模式的区别主要在于它们的意图和设计目的。装饰器模式主要用于为对象动态添加新的功能和行为,而代理模式主要用于控制对原对象的访问,处理一些不想或不能由原对象处理的事情。
// 抽象主题
interface Subject {
void request();
}
// 真实主题
class RealSubject implements Subject {
@Override
public void request() {
System.out.println("RealSubject request");
}
}
// 代理
class Proxy implements Subject {
private RealSubject realSubject;
@Override
public void request() {
if (realSubject == null) {
realSubject = new RealSubject();
}
preRequest();
realSubject.request();
postRequest();
}
private void preRequest() {
System.out.println("Proxy preRequest");
}
private void postRequest() {
System.out.println("Proxy postRequest");
}
}
// 测试代码
public class ProxyPatternDemo {
public static void main(String[] args) {
Proxy proxy = new Proxy();
proxy.request();
}
}
在这个示例中,RealSubject
是真实主题,Proxy
是代理。代理在调用真实主题的request
方法前后,都进行了一些额外的操作。这样,客户端就可以通过代理来间接访问真实主题,同时还可以进行一些额外的操作。