目录
一、设计模式
1️⃣创建型设计模式(常用:单例、工厂、抽象工厂)
2️⃣结构型设计模式(常用:适配器、装饰者、外观、代理)
3️⃣行为型设计模式(常用:观察者、策略、模板方法、命令)
二、其他
4️⃣面试中关于设计模式如何考察(思考该如何回答?在实际项目中如何应用?)
具体详细说明如下:
带着问题学习:👀什么是设计模式?设计模式包含哪些?每个设计模式的特点又都是什么?每个设计模式有都适用于哪些场景?
设计模式是软件工程中的一种解决问题的方法论,它提供了一套经过测试和验证的代码设计原则和模板。设计模式有助于构建可维护、可扩展和可重用的代码,提高软件系统的灵活性和可靠性。在Java中,常用的设计模式包括创建型模式、结构型模式和行为型模式。在Java中,设计模式包括常见的23种,常用6~8种。在Java中,常用的设计模式📣包括创建型模式、结构型模式和行为型模式。下面将详细讨论这些设计模式,并举例说明其用法。
一、设计模式
设计模式的原则(六大原则):
-
单一职责原则(Single Responsibility Principle, SRP):这个原则要求一个类应该只有一个引起变化的原因。在Java中,可以通过将类和方法拆分成更小的部分,使得每个类和方法只负责一个特定的职责。
-
开放-封闭原则(Open-Closed Principle, OCP):这个原则要求软件实体应该对扩展开放,对修改封闭。在Java中,可以通过使用接口、抽象类和设计模式(如策略模式、装饰器模式)来实现。
-
里氏替换原则(Liskov Substitution Principle, LSP):在Java中,这个原则要求子类可以替换父类并且仍然能够在程序中工作。通过合理设计继承关系和使用接口,可以实现这个原则。
-
依赖倒置原则(Dependency Inversion Principle, DIP):这个原则要求高层模块不应该依赖于低层模块,两者都应该依赖于抽象。在Java中,可以通过依赖注入(如使用Spring框架)来实现。
-
接口隔离原则(Interface Segregation Principle, ISP):这个原则要求一个类不应该强迫实现它用不到的接口。在Java中,可以通过定义多个小接口,避免一个庞大的接口。
-
最少知识原则(Least Knowledge Principle, LKP):这个原则要求一个软件实体尽可能少地了解其他实体。在Java中,可以通过合理的使用设计模式来实现。
1️⃣创建型设计模式(常用:单例、工厂、抽象工厂)
- 单例模式(Singleton):确保一个类只有一个实例,并提供一个全局访问点。典型的应用场景是线程池、数据库连接池等。或比如在一个Web应用程序中,可能需要一个全局的配置管理类,保证程序运行期间只有一个配置实例。示例代码如下:
在项目中通常会有一些需要全局唯一的资源或服务,比如配置管理器、线程池等。使用单例模式可以确保只创建一个实例,避免资源浪费和不一致性。
// 示例一
public class Singleton {
private static Singleton instance;
private Singleton() {}
public static Singleton getInstance() {
if (instance == null) {
synchronized (Singleton.class) {
if (instance == null) {
instance = new Singleton();
}
}
}
return instance;
}
}
// ==================================================================
// 示例二
public class AppConfig {
private static AppConfig instance;
private AppConfig() {
// 私有构造函数,防止外部实例化
}
public static AppConfig getInstance() {
if (instance == null) {
instance = new AppConfig();
}
return instance;
}
public String getConfiguration(String key) {
// 实现获取配置信息的方法
}
}
- 工厂模式(Factory):工厂模式通过提供一个公共的接口来实例化对象(定义一个用于创建对象的接口),隐藏了具体实现类的创建逻辑,让子类决定实例化哪个类。常见的场景是数据库操作类的创建。工厂方法模式(Factory Method Pattern):在项目中经常用于创建对象,尤其是在需要根据条件创建不同类型对象时。比如,可以根据不同的请求参数创建不同类型的数据库连接、日志记录器等对象。
在项目中,可以创建一个抽象工厂接口和多个具体工厂实现类,用于根据条件创建不同类型的对象。例如,可以创建一个数据库连接的抽象工厂接口,如ConnectionFactory
,并实现多个具体工厂类,如MysqlConnectionFactory
和PostgresqlConnectionFactory
。在需要创建数据库连接时,通过工厂方法根据条件创建不同类型的数据库连接对象。
public interface Database {
void connect();
void disconnect();
}
public class MySQLDatabase implements Database {
@Override
public void connect() {
// 连接MySQL数据库的具体逻辑
}
@Override
public void disconnect() {
// 断开连接MySQL数据库的具体逻辑
}
}
public class OracleDatabase implements Database {
@Override
public void connect() {
// 连接Oracle数据库的具体逻辑
}
@Override
public void disconnect() {
// 断开连接Oracle数据库的具体逻辑
}
}
public class DatabaseFactory {
public static Database createDatabase(String type) {
if (type.equals("MySQL")) {
return new MySQLDatabase();
} else if (type.equals("Oracle")) {
return new OracleDatabase();
}
throw new IllegalArgumentException("Invalid database type: " + type);
}
}
比如在一个图形界面应用程序中,根据用户选择的图形类型创建相应的图形对象,可以用工厂模式。示例代码如下:
public interface Shape {
void draw();
}
public class Circle implements Shape {
@Override
public void draw() {
System.out.println("Draw a circle");
}
}
public class Square implements Shape {
@Override
public void draw() {
System.out.println("Draw a square");
}
}
public class ShapeFactory {
public Shape createShape(String type) {
if ("circle".equalsIgnoreCase(type)) {
return new Circle();
} else if ("square".equalsIgnoreCase(type)) {
return new Square();
}
return null;
}
}
- 抽象工厂模式(Abstract Factory):提供一个创建一系列相关或相互依赖对象的接口,而无需指定它们具体的类。典型的应用场景是GUI库,其中不同操作系统下的按钮、文本框等控件有不同的具体实现。
public interface Button {
void render();
}
public class WindowsButton implements Button {
@Override
public void render() {
// 在Windows操作系统下渲染按钮的具体逻辑
}
}
public class MacOSButton implements Button {
@Override
public void render() {
// 在MacOS操作系统下渲染按钮的具体逻辑
}
}
public interface GUIFactory {
Button createButton();
}
public class WindowsGUIFactory implements GUIFactory {
@Override
public Button createButton() {
return new WindowsButton();
}
}
public class MacOSGUIFactory implements GUIFactory {
@Override
public Button createButton() {
return new MacOSButton();
}
}
2️⃣结构型设计模式(常用:适配器、装饰者、外观、代理)
- 适配器模式(Adapter):将一个类的接口转换为客户希望的另一个接口。
在项目中需要将一个接口转换成另一个客户端需要的接口时,可以使用适配器模式。比如,将第三方库的接口适配成项目内部需要的接口、旧版本的代码中使用新版本的接口。
public interface Target {
void request();
}
public class Adaptee {
public void specificRequest() {
// 适配者类的特殊请求的具体逻辑
}
}
public class Adapter implements Target {
private Adaptee adaptee;
public Adapter(Adaptee adaptee) {
this.adaptee = adaptee;
}
@Override
public void request() {
adaptee.specificRequest();
}
}
- 装饰者模式(Decorator):动态地给一个对象添加一些额外的职责。装饰器模式允许动态地向对象添加额外的行为。它是通过将对象包装在一个装饰器类中来实现的,该类有与原始对象相同的接口。
在项目中需要对一个对象进行动态地添加功能或修改现有功能时,可以使用装饰器模式。比如,对已有的对象进行包装,添加日志记录、性能监控等功能。
public interface Component {
void operation();
}
public class ConcreteComponent implements Component {
@Override
public void operation() {
// 原始对象的操作
}
}
public abstract class Decorator implements 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();
// 装饰器的额外操作A
}
}
public class ConcreteDecoratorB extends Decorator {
public ConcreteDecoratorB(Component component) {
super(component);
}
@Override
public void operation() {
super.operation();
// 装饰器的额外操作B
}
}
比如在一个咖啡点单系统中,可以根据顾客的选择动态地为咖啡添加不同的调料,而不需要修改咖啡类的代码。示例代码如下:
public interface Coffee {
double cost(); // 咖啡的价格
}
public class Espresso implements Coffee {
@Override
public double cost() {
return 2.0; // 浓缩咖啡的价格
}
}
public abstract class CoffeeDecorator implements Coffee {
protected Coffee decoratedCoffee;
public CoffeeDecorator(Coffee decoratedCoffee) {
this.decoratedCoffee = decoratedCoffee;
}
@Override
public double cost() {
return decoratedCoffee.cost();
}
}
public class MilkDecorator extends CoffeeDecorator {
public MilkDecorator(Coffee decoratedCoffee) {
super(decoratedCoffee);
}
@Override
public double cost() {
return super.cost() + 0.5; // 添加牛奶的价格
}
}
public class SugarDecorator extends CoffeeDecorator {
public SugarDecorator(Coffee decoratedCoffee) {
super(decoratedCoffee);
}
@Override
public double cost() {
return super.cost() + 0.3; // 添加糖的价格
}
}
public class Main {
public static void main(String[] args) {
Coffee espresso = new Espresso();
System.out.println("Price of espresso: " + espresso.cost());
Coffee milkCoffee = new MilkDecorator(espresso);
System.out.println("Price of milk coffee: " + milkCoffee.cost());
Coffee sugarMilkCoffee = new SugarDecorator(milkCoffee);
System.out.println("Price of sugar milk coffee: " + sugarMilkCoffee.cost());
}
}
- 外观模式(Facade Pattern) 外观模式提供了一个统一的接口,用于访问一组复杂子系统的功能。它封装了子系统的复杂性,提供了一个更简单和易用的接口给客户端使用。
public class SubsystemA {
public void operationA() {
// 子系统A的操作
}
}
public class SubsystemB {
public void operationB() {
// 子系统B的操作
}
}
public class SubsystemC {
public void operationC() {
// 子系统C的操作
}
}
public class Facade {
private SubsystemA subSystemA;
private SubsystemB subSystemB;
private SubsystemC subSystemC;
public Facade() {
this.subSystemA = new SubsystemA();
this.subSystemB = new SubsystemB();
this.subSystemC = new SubsystemC();
}
public void operation() {
subSystemA.operationA();
subSystemB.operationB();
subSystemC.operationC();
}
}
- 代理模式(Proxy):为其他对象提供一种代理以控制对这个对象的访问。
代理模式是一种结构型设计模式,它允许一个对象(代理)代表另一个对象进行访问控制。代理模式通常用于控制对其他对象的访问,以提供为其他对象提供一个替代接口或者对其进行保护。代理对象和真实对象之间的关系可以分为静态代理和动态代理两种形式。
在代理模式中,通常涉及以下几个角色:
- 抽象主题(Subject):定义了代理对象和真实对象的共同接口,这样代理对象和真实对象就可以对外提供一致的服务。
- 真实主题(Real Subject):实际完成业务逻辑的对象,是代理对象所代表的对象。
- 代理(Proxy):包含了对真实主题的引用,并且可以对其进行访问控制,提供额外的功能,或者对真实对象进行保护。
在Java中,代理模式常常使用在网络编程、安全控制、日志记录和缓存等场景中,例如RMI(远程方法调用)、Spring AOP(面向切面编程)等都是代理模式的经典应用。以下是一个简单的Java代码示例,演示了代理模式的实现:
// 抽象主题接口
interface Image {
void display();
}
// 真实主题类
class RealImage implements Image {
private String fileName;
public RealImage(String fileName) {
this.fileName = fileName;
loadFromDisk(fileName);
}
@Override
public void display() {
System.out.println("Displaying " + fileName);
}
private void loadFromDisk(String fileName) {
System.out.println("Loading " + fileName + " from disk");
}
}
// 代理类
class ProxyImage implements Image {
private RealImage realImage;
private String fileName;
public ProxyImage(String fileName) {
this.fileName = fileName;
}
@Override
public void display() {
if (realImage == null) {
realImage = new RealImage(fileName);
}
realImage.display();
}
}
// 客户端代码
public class ProxyPatternDemo {
public static void main(String[] args) {
Image image = new ProxyImage("test.jpg");
// 图像将从磁盘加载
image.display();
System.out.println("");
// 图像不需要从磁盘加载
image.display();
}
}
Image
接口是抽象主题,RealImage
类是真实主题,ProxyImage
类是代理。当客户端调用 display
方法时,代理对象 ProxyImage
会首先检查是否已经创建了真实对象 RealImage
,如果没有,则创建并调用真实对象的 display
方法;如果已经存在真实对象,则直接调用真实对象的 display
方法。这样就实现了对真实对象的访问控制。在该示例中,代理模式的应用场景是延迟加载,即真实对象的创建可以延迟到真正需要使用的时候。
总的来说,代理模式可以帮助我们统一对真实对象的访问控制,可以在不改变真实对象的情况下增加额外的功能,例如安全性检测、性能优化、日志记录等。
3️⃣行为型设计模式(常用:观察者、策略、模板方法、命令)
- 观察者模式(Observer):定义对象间的一对多依赖关系,当一个对象的状态发生改变时,所有依赖它的对象都会得到通知并自动更新。
在项目中,可以用观察者模式实现事件通知和监听机制。例如,可以创建一个事件管理器类,并将需要监听事件的对象注册为观察者。当事件发生时,通知所有注册的观察者进行相应的处理。
观察者模式定义了一种一对多的依赖关系,当被观察者的状态发生改变时,所有依赖于它的观察者都会得到通知并更新。典型的应用场景是GUI编程中的事件监听和消息通知。
import java.util.ArrayList;
import java.util.List;
public interface Observer {
void update();
}
public class ConcreteObserver implements Observer {
@Override
public void update() {
// 观察者的具体更新逻辑
}
}
public interface Subject {
void attach(Observer observer);
void detach(Observer observer);
void notifyObservers();
}
public class ConcreteSubject implements Subject {
private List<Observer> observers = new ArrayList<>();
@Override
public void attach(Observer observer) {
observers.add(observer);
}
@Override
public void detach(Observer observer) {
observers.remove(observer);
}
@Override
public void notifyObservers() {
for (Observer observer : observers) {
observer.update();
}
}
}
在需要实现消息订阅和发布功能时,可以使用观察者模式。比如在一个新闻发布系统中,新闻发布者发布新闻时,订阅者会收到通知,并进行相应处理。示例代码如下:
public interface Observer {
void update(String news); // 定义更新方法
}
public interface Subject {
void registerObserver(Observer observer); // 注册观察者
void removeObserver(Observer observer); // 移除观察者
void notifyObservers(); // 通知观察者
}
public class NewsPublisher 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() {
for (Observer observer : observers) {
observer.update("New news is available!");
}
}
public void publishNews() {
// 发布新闻
notifyObservers(); // 发送通知
}
}
public class NewsSubscriber implements Observer {
@Override
public void update(String news) {
System.out.println("Received news: " + news);
// 处理接收到的新闻
}
}
- 策略模式(Strategy):定义一系列算法,把它们封装起来,并且使它们可以互相替换。
策略模式定义了一系列可互换的算法,并使得算法的变化独立于使用它的客户端。通过封装算法,可以在运行时选择不同的算法。示例1:
public interface SortStrategy {
void sort(int[] data);
}
public class BubbleSortStrategy implements SortStrategy {
@Override
public void sort(int[] data) {
// 冒泡排序的具体实现
}
}
public class QuickSortStrategy implements SortStrategy {
@Override
public void sort(int[] data) {
// 快速排序的具体实现
}
}
public class Sorter {
private SortStrategy strategy;
public Sorter(SortStrategy strategy) {
this.strategy = strategy;
}
public void sort(int[] data) {
strategy.sort(data);
}
}
在项目中需要根据不同的策略进行不同的操作时,可以使用策略模式。比如在一个电商系统中,根据不同的活动使用不同的优惠策略,可以使用策略模式。示例2代码如下:
public interface DiscountStrategy {
double applyDiscount(double originalPrice); // 应用折扣策略
}
public class RegularCustomerDiscount implements DiscountStrategy {
@Override
public double applyDiscount(double originalPrice) {
return originalPrice * 0.9; // 正常客户打9折
}
}
public class VIPCustomerDiscount implements DiscountStrategy {
@Override
public double applyDiscount(double originalPrice) {
return originalPrice * 0.8; // VIP客户打8折
}
}
public class PriceCalculator {
private DiscountStrategy discountStrategy;
public PriceCalculator(DiscountStrategy discountStrategy) {
this.discountStrategy = discountStrategy;
}
public double calculateFinalPrice(double originalPrice) {
return discountStrategy.applyDiscount(originalPrice);
}
}
- 模板方法模式(Template Method):定义一个操作中的算法的骨架,而将一些步骤延迟到子类中实现。
模板方法模式是一种行为型设计模式,它定义了一个算法的框架,并允许子类在不改变该算法结构的情况下重新定义该算法的某些步骤。
以下是一个简单的模板方法模式示例,假设我们有一个制作饮料的类:饮料
public abstract class Beverage {
// 制作饮料的模板方法
public final void prepareBeverage() {
boilWater();
brew();
pourInCup();
addCondiments();
}
// 将水煮沸
public void boilWater() {
System.out.println("Boiling water");
}
// 泡制饮料
public abstract void brew();
// 将饮料倒入杯中
public void pourInCup() {
System.out.println("Pouring into cup");
}
// 添加调料
public abstract void addCondiments();
}
现在我们可以创建具体的饮料类,比如咖啡和茶:
public class Coffee extends Beverage {
@Override
public void brew() {
System.out.println("Dripping Coffee through filter");
}
@Override
public void addCondiments() {
System.out.println("Adding Sugar and Milk");
}
}
public class Tea extends Beverage {
@Override
public void brew() {
System.out.println("Steeping the tea");
}
@Override
public void addCondiments() {
System.out.println("Adding Lemon");
}
}
在这个示例中,Beverage 类定义了一个模板方法 prepareBeverage(),该方法包含了制作饮料的算法框架,并调用了一系列抽象方法 boilWater()、brew()、pourInCup() 和 addCondiments()。具体的饮料类如 Coffee 和 Tea 可以继承 Beverage 并实现这些抽象方法来自定义制作过程。
通过模板方法模式,我们可以将共享的制作流程放在父类中,同时允许子类根据自己的特性来实现具体步骤,从而实现了代码的重用和灵活性。
- 命令模式(Command Pattern) 命令模式将一个请求封装为一个对象,并提供执行该请求的方法。这样可以让客户端参数化请求,即可以用不同的请求对象进行参数化。
public interface Command {
void execute();
}
public class ConcreteCommand implements Command {
private Receiver receiver;
public ConcreteCommand(Receiver receiver) {
this.receiver = receiver;
}
@Override
public void execute() {
receiver.action();
}
}
public class Receiver {
public void action() {
// 接收者的具体操作
}
}
public class Invoker {
private Command command;
public void setCommand(Command command) {
this.command = command;
}
public void executeCommand() {
command.execute();
}
}
按照其他的作用范围也可以分为:
以上是一些常见的设计模式在Java中的应用示例。设计模式是软件工程师必备的工具之一,通过学习和应用设计模式,可以提高代码的可读性、可维护性和可扩展性,帮助构建高质量的软件系统。
二、其他问答
4️⃣面试中关于设计模式如何考察
(思考该如何回答?在实际项目中如何应用?)
在实际项目开发中,常用和面试经常问的设计模式包括工厂方法模式、单例模式、观察者模式、策略模式、装饰器模式和适配器模式。在面试中,通常会问及如何使用这些设计模式来解决特定的问题,以考察面试者对设计模式的理解和应用能力。
在面试时,可以按照以下结构回答与设计模式相关的问题:
-
了解问题: 首先要确保对于面试官提出的问题有充分的理解,明确问题的背景和需求。
-
解释设计模式: 对于问及的设计模式,解释设计模式的基本概念和作用,以及在什么场景下常常被使用。
-
描述实际场景: 提供一个实际的项目开发或者工程中的场景,说明在这个场景下如何应用该设计模式。可以使用自己曾经经历的项目经验,或者构建一个简单的场景来说明。
-
优点和缺点: 讨论该设计模式在具体场景中的优点和缺点,以及为什么选择该设计模式而不是其他设计模式。
-
举例说明: 如果可能的话,举出更多实际的例子来说明该设计模式的应用,以及它如何帮助解决了具体问题。
-
总结: 结束时对于该设计模式的应用做一个简单的总结,并强调你的理解和应用能力。
在面试中,深入举例说明自己在实际项目中如何应用设计模式,以及对设计模式的理解程度,会给面试官留下良好的印象,展示自己的技术能力和经验。
下面是一些高频且容易被考察的设计模式问题以及问题的答案:
- 解释什么是设计模式?设计模式是什么目的?
答:设计模式是针对常见软件设计问题提出的可重用解决方案。它的目的是提供一种通用的解决方案,以便在软件开发中用于解决特定类型的问题。
- 请列举常用的创建型设计模式?
答:常用的创建型设计模式包括工厂方法模式、抽象工厂模式、单例模式、建造者模式和原型模式。
- 什么是单例模式?请写一个线程安全的单例模式的示例代码。
答:单例模式是一种保证一个类仅有一个实例,并提供一个全局访问点的设计模式。
示例代码可以是:
public class Singleton {
private static Singleton instance; private Singleton() {
} public static synchronized Singleton getInstance() {
if (instance == null) {
instance = new Singleton();
}
return instance;
}
}
-
请列举常用的结构型设计模式?
答:常用的结构型设计模式包括适配器模式、装饰器模式、代理模式、外观模式、桥接模式、组合模式和享元模式。
-
什么是适配器模式?请写一个适配器模式的示例代码。
答:适配器模式是将一个类的接口转换成客户希望的另外一个接口。示例代码可以是:
public interface MediaPlayer {
void play(String audioType, String fileName);
}
public interface AdvancedMediaPlayer {
void playVlc(String fileName);
void playMp4(String fileName);
}
public class VlcPlayer implements AdvancedMediaPlayer {
@Override
public void playVlc(String fileName) {
System.out.println("Playing vlc file. Name: " + fileName);
}
@Override
public void playMp4(String fileName) {
// Do nothing
}
}
public class MediaAdapter implements MediaPlayer {
AdvancedMediaPlayer advancedMusicPlayer;
public MediaAdapter(String audioType){
if(audioType.equalsIgnoreCase("vlc") ){
advancedMusicPlayer = new VlcPlayer();
}
}
@Override
public void play(String audioType, String fileName) {
if(audioType.equalsIgnoreCase("vlc")){
advancedMusicPlayer.playVlc(fileName);
}
}
}
-
请列举常用的行为型设计模式?
答:常用的行为型设计模式包括策略模式、模板方法模式、观察者模式、迭代器模式、责任链模式、命令模式、备忘录模式、状态模式等。
-
什么是策略模式?请写一个策略模式的示例代码。
答:策略模式定义了一系列算法,将每个算法封装起来,并使它们可以互相替换。示例代码可以是:
public interface Strategy {
int doOperation(int num1, int num2);
}
public class OperationAdd implements Strategy{
@Override
public int doOperation(int num1, int num2) {
return num1 + num2;
}
}
public class Context {
private Strategy strategy;
public Context(Strategy strategy){
this.strategy = strategy;
}
public int executeStrategy(int num1, int num2){
return strategy.doOperation(num1, num2);
}
}
- 什么是观察者模式?请写一个观察者模式的示例代码。
答:观察者模式定义了对象间的一对多依赖关系,当一个对象的状态发生改变时,所有依赖它的对象都将得到通知并自动更新。示例代码可以是:
public interface Observer {
void update(String message);
}
public interface Subject {
void registerObserver(Observer observer);
void removeObserver(Observer observer);
void notifyObservers(String message);
}
public 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);
}
}
}
- 请解释装饰器模式的用途,并写一个装饰器模式的示例代码。
答:装饰器模式允许向一个现有的对象添加新的功能,同时又不改变其结构。示例代码可以是:
public interface Shape {
void draw();
}
public class Circle implements Shape {
@Override
public void draw() {
System.out.println("Shape: Circle");
}
}
public abstract class ShapeDecorator implements Shape {
protected Shape decoratedShape;
public ShapeDecorator(Shape decoratedShape){
this.decoratedShape = decoratedShape;
}
public void draw(){
decoratedShape.draw();
}
}
public class RedShapeDecorator extends ShapeDecorator {
public RedShapeDecorator(Shape decoratedShape) {
super(decoratedShape);
}
@Override
public void draw() {
decoratedShape.draw();
setRedBorder(decoratedShape);
}
private void setRedBorder(Shape decoratedShape){
System.out.println("Border Color: Red");
}
}
- 什么是工厂方法模式?请写一个工厂方法模式的示例代码。
答:工厂方法模式定义了一个创建对象的接口,但由子类决定要实例化的类是哪一个。示例代码可以是:
public interface Shape {
void draw();
}
public class Circle implements Shape {
@Override
public void draw() {
System.out.println("Inside Circle::draw() method.");
}
}
public class Rectangle implements Shape {
@Override
public void draw() {
System.out.println("Inside Rectangle::draw() method.");
}
}
public interface ShapeFactory {
Shape createShape();
}
public class CircleFactory implements ShapeFactory {
@Override
public Shape createShape() {
return new Circle();
}
}
public class RectangleFactory implements ShapeFactory {
@Override
public Shape createShape() {
return new Rectangle();
}
}
- 简要介绍一下代理模式,并写一个代理模式的示例代码。
答:代理模式为其他对象提供一种方式来控制对这个对象的访问。示例代码可以是:
public interface Image {
void display();
}
public class RealImage implements Image {
private String fileName;
public RealImage(String fileName) {
this.fileName = fileName;
}
@Override
public void display() {
System.out.println("Displaying " + fileName);
}
}
public class ProxyImage implements Image {
private RealImage realImage;
private String fileName;
public ProxyImage(String fileName) {
this.fileName = fileName;
}
@Override
public void display() {
if (realImage == null) {
realImage = new RealImage(fileName);
}
realImage.display();
}
}
- 什么是责任链模式?请写一个责任链模式的示例代码。
答:责任链模式为请求创建了一个接收者对象的链。示例代码可以是:
public abstract class Logger {
public static int INFO = 1;
public static int DEBUG = 2;
public static int ERROR = 3;
protected int level;
protected Logger nextLogger;
public void setNextLogger(Logger nextLogger) {
this.nextLogger = nextLogger;
}
public void logMessage(int level, String message) {
if (this.level <= level) {
write(message);
}
if (nextLogger != null) {
nextLogger.logMessage(level, message);
}
}
abstract protected void write(String message);
}
public class ConsoleLogger extends Logger {
public ConsoleLogger(int level) {
this.level = level;
}
protected void write(String message) {
System.out.println("Standard Console::Logger: " + message);
}
}
public class ErrorLogger extends Logger {
public ErrorLogger(int level) {
this.level = level;
}
protected void write(String message) {
System.out.println("Error Console::Logger: " + message);
}
}
public class FileLogger extends Logger {
public FileLogger(int level) {
this.level = level;
}
protected void write(String message) {
System.out.println("File::Logger: " + message);
}
}
- 何谓模板方法模式?请写一个模板方法模式的示例代码。
答:模板方法模式定义了一个算法的骨架,并允许子类为一个或多个步骤提供实现。示例代码可以是:
public abstract class Game {
abstract void initialize();
abstract void startPlay();
abstract void endPlay();
public final void play() {
initialize();
startPlay();
endPlay();
}
}
public class Cricket extends Game {
@Override
void initialize() {
System.out.println("Cricket Game Initialized! Start playing.");
}
@Override
void startPlay() {
System.out.println("Cricket Game Started. Enjoy the game!");
}
@Override
void endPlay() {
System.out.println("Cricket Game Finished!");
}
}
public class Football extends Game {
@Override
void initialize() {
System.out.println("Football Game Initialized! Start playing.");
}
@Override
void startPlay() {
System.out.println("Football Game Started. Enjoy the game!");
}
@Override
void endPlay() {
System.out.println("Football Game Finished!");
}
}
- 什么是迭代器模式?请写一个迭代器模式的示例代码。
答:迭代器模式提供一种方法顺序访问一个聚合对象中的各个元素,而又不暴露其内部的表示。示例代码可以是:
public interface Iterator {
boolean hasNext();
Object next();
}
public interface Container {
Iterator getIterator();
}
public class NameRepository implements Container {
public String names[] = {"Robert", "John", "Julie", "Lora"};
@Override
public Iterator getIterator() {
return new NameIterator();
}
private class NameIterator implements Iterator {
int index;
@Override
public boolean hasNext() {
return index < names.length;
}
@Override
public Object next() {
if(this.hasNext()) {
return names[index++];
}
return null;
}
}
}
- 创建型设计模式中的抽象工厂模式的作用是什么?请写一个抽象工厂模式的示例代码。
答:抽象工厂模式提供了一种方式,可以以独立于产品的方式创建一系列相关或依赖对象。示例代码可以是:
public interface Shape {
void draw();
}
public class RoundedRectangle implements Shape {
@Override
public void draw() {
System.out.println("Inside RoundedRectangle::draw() method.");
}
}
public class RoundedSquare implements Shape {
@Override
public void draw() {
System.out.println("Inside RoundedSquare::draw() method.");
}
}
public abstract class AbstractFactory {
abstract Shape getShape(String shapeType);
}
public class RoundedShapeFactory extends AbstractFactory {
@Override
public Shape getShape(String shapeType) {
if(shapeType.equalsIgnoreCase("RECTANGLE")){
return new RoundedRectangle();
} else if(shapeType.equalsIgnoreCase("SQUARE")){
return new RoundedSquare();
}
return null;
}
}
这些问题和示例代码可以帮助面试者巩固对设计模式的理解。