java常见的面试设计模式
- 看这里,动画描述很好
- 创建型模式
-
- 工厂方法模式
-
- 目的
- 结构
- 场景
- 优缺点
- 示例代码
-
- button
- factory
- Demo.java: 客户端代码
- 抽象工厂模式
-
- 目的
- 结构
- 场景
- 优缺点
- 示例代码
-
- buttons: 第一产品层次结构
- checkboxes: 二是产品层次结构
- factories
- Demo
- 生成器模式
-
- 目的
- 结构
- 场景
- 优缺点
- 示例代码
-
- builders
- cars
- components
- director
- Demo.java: 客户端代码
- 原型模式
-
- 目的
- 结构
- 场景
- 优缺点
- 示例代码
-
- shapes: 形状列表
- Demo.java: 克隆示例
- 单例模式
-
- 问题
- 目的
- 步骤
- 结构
- 场景
- 优缺点
- 示例代码
-
- 基本单例(懒汉模式 延迟加载(单线程)
- 基本单例(懒汉模式 延迟加载(多线程)
- 延迟加载的线程安全单例
- 其他
-
- 比较工厂模式
-
- 工厂
- 构建方法
- 静态构建 (或工厂) 方法
- 简单工厂
- 工厂方法
- 抽象工厂
- 结构型模式
-
- 适配器模式
-
- 运作方式
- 目的
- 结构
- 场景
- 优缺点
- 示例代码
-
- round
- square
- adapters
- Demo.java: 客户端代码
- 组合模式
-
- 运作方式
- 目的
- 结构
- 场景
- 优缺点
- 示例代码
-
- shapes
- editor
- Demo.java: 客户端代码
- 装饰模式
-
- 问题
- 运作方式
- 目的
- 结构
- 场景
- 优缺点
- 示例代码
-
- Source
- decorators
- Demo.java: 客户端代码
- 外观模式
-
- 问题
- 运作方式
- 目的
- 结构
- 场景
- 优缺点
- 示例代码
-
- some_complex_media_library: 复杂的视频转换程序库
- facade
- Demo.java: 客户端代码
- 代理模式
-
- 问题
- 运作方式
- 目的
- 结构
- 场景
- 优缺点
- 示例代码
- @Deprecated
-
- 单例模式
-
- 懒汉式单例
- 饿汉式单例
- 区别
- 工厂模式
-
- 应用
- 适配器模式
- 代理模式
看这里,动画描述很好
设计模式
创建型模式
提供了创建对象的机制
,提升现有代码的灵活性和可重用性
工厂方法模式
目的
生产不同类型的产品
针对不同类型的操作系统
生成不同的 GUI 弹窗对象
结构
场景
无法预测对象的准确性
别及其依赖关系coe>时, 可使用工厂方法。
工厂方法将创建产品的代码
与实际使用产品
的代码分离, 从而能在不影响其他代码的情况下
扩展产品创建部分代码。
例如, 如果需要向应用中添加一种新产品
, 你只需要开发新的创建者子类
, 然后重写其工厂方法
即可。
优缺点
避免 创建者 和 具体产品 之间的 耦合
单一职责 原则。 可以将 产品创建代码 放在 程序的单一位置,使 代码更容易维护
开闭原则。 无需更改 现有客户端代码, 就可以 在程序中 引入 新的 产品类型
需要 引入 许多新的子类, 代码可能会因此变得更复杂
示例代码
button
package refactoring_guru.factory_method.example.buttons;
/** * Common interface for all buttons. */
public interface Button {
void render();
void onClick();
}
package refactoring_guru.factory_method.example.buttons;
/** * HTML button implementation. */
public class HtmlButton implements Button {
public void render() {
System.out.println("<button>Test Button</button>");
onClick();
}
public void onClick() {
System.out.println("Click! Button says - 'Hello World!'");
}
}
package refactoring_guru.factory_method.example.buttons;
/** * Windows button implementation. */
public class WindowsButton implements Button {
...
public void render() {
...
onClick();
}
public void onClick() {
...
}
}
factory
package refactoring_guru.factory_method.example.factory;
import refactoring_guru.factory_method.example.buttons.Button;
/** * Base factory class. Note that "factory" is merely a role for the class. It * should have some core business logic which needs different products to be * created. */
public abstract class Dialog {
public void renderWindow() {
// ... other code ...
Button okButton = createButton();
okButton.render();
}
/** * Subclasses will override this method in order to create specific button * objects. */
public abstract Button createButton();
}
package refactoring_guru.factory_method.example.factory;
import refactoring_guru.factory_method.example.buttons.Button;
import refactoring_guru.factory_method.example.buttons.HtmlButton;
/** * HTML Dialog will produce HTML buttons. */
public class HtmlDialog extends Dialog {
@Override
public Button createButton() {
return new HtmlButton();
}
}
package refactoring_guru.factory_method.example.factory;
import refactoring_guru.factory_method.example.buttons.Button;
import refactoring_guru.factory_method.example.buttons.WindowsButton;
/** * Windows Dialog will produce Windows buttons. */
public class WindowsDialog extends Dialog {
@Override
public Button createButton() {
return new WindowsButton();
}
}
Demo.java: 客户端代码
package refactoring_guru.factory_method.example;
import refactoring_guru.factory_method.example.factory.Dialog;
import refactoring_guru.factory_method.example.factory.HtmlDialog;
import refactoring_guru.factory_method.example.factory.WindowsDialog;
/** * Demo class. Everything comes together here. */
public class Demo {
private static Dialog dialog;
public static void main(String[] args) {
configure();
runBusinessLogic();
}
/** * The concrete factory is usually chosen depending on configuration or * environment options. */
static void configure() {
if (System.getProperty("os.name").equals("Windows 10")) {
dialog = new WindowsDialog();
} else {
dialog = new HtmlDialog();
}
}
/** * All of the client code should work with factories and products through * abstract interfaces. This way it does not care which factory it works * with and what kind of product it returns. */
static void runBusinessLogic() {
dialog.renderWindow();
}
}
抽象工厂模式
一系列相关产品, 例如 椅子Chair 、 沙发Sofa和 咖啡桌CoffeeTable 。
系列产品的不同变体。 例如, 你可以使用 现代Modern 、 维多利亚Victorian 、 装饰风艺术ArtDeco等风格生成 椅子 、 沙发和 咖啡桌 。
设法生成同一系列每件家具对象
, 这样才能确保其风格一致
。 如果顾客收到的家具风格不一样, 他们可不会开心。 客户端无需了解工厂类, 也不用管工厂类创建出的椅子类型
。 无论是现代风格, 还是维多利亚风格的椅子, 对于客户端来说没有分别, 它只需要同一系列的桌椅
就可以了。此外, 无论工厂返回的是何种椅子变体, 它都会和由同一工厂对象创建的沙发或咖啡桌风格一致
目的
创建一系列相关的对象
针对不同类型的操作系统
生成不同
系列
的 GUI 弹窗对象
结构
场景
需要与多个不同系列的相关产品
交互, 但是由于无法提前获取相关信息
, 或者出于对未来扩展性的考虑
, 你不希望代码基于产品的具体类
进行构建, 在这种情况下, 你可以使用抽象工厂。
抽象工厂为你提供了一个接口, 可用于创建每个系列产品的对象
。 只要代码通过该接口创建对象
, 那么你就不会生成与应用程序已生成的产品类型不一致的产品
在设计良好的程序中, 每个类仅负责一件事。 如果一个类与多种类型产品交互
, 就可以考虑将工厂方法抽取到独立的工厂类
或具备完整功能的抽象工厂类
中。
优缺点
可以确保 同一工厂 生成的产品 相互匹配
可以避免 客户端 和 具体产品 代码的耦合
单一职责原则。 可以将产品 生成代码 抽取到同一位置, 使得代码易于维护
开闭原则。 向应用程序中引入新产品变体时, 无需修改客户端代码。
由于采用该模式需要向应用中引入众多接口和类, 代码可能会比之前更加复杂。
示例代码
buttons: 第一个产品层次结构
public interface Button {
void paint();
}
public class MacOSButton implements Button {
@Override
public void paint() {
System.out.println("You have created MacOSButton.");
}
}
public class WindowsButton implements Button {
@Override
public void paint() {
System.out.println("You have created WindowsButton.");
}
}
checkboxes: 第二个产品层次结构
public interface Checkbox {
void paint();
}
public class MacOSCheckbox implements Checkbox {
@Override
public void paint() {
System.out.println("You have created MacOSCheckbox.");
}
}
public class WindowsCheckbox implements Checkbox {
@Override
public void paint() {
System.out.println("You have created WindowsCheckbox.");
}
}
factories
public interface GUIFactory {
Button createButton();
Checkbox createCheckbox();
}
public class MacOSFactory implements GUIFactory {
@Override
public Button createButton() {
return new MacOSButton();
}
@Override
public Checkbox createCheckbox() {
return new MacOSCheckbox();
}
}
public class WindowsFactory implements GUIFactory {
@Override
public Button createButton() {
return new WindowsButton();
}
@Override
public Checkbox createCheckbox() {
return new WindowsCheckbox();
}
}
Demo
public class Application {
private Button button;
private Checkbox checkbox;
public Application(GUIFactory factory) {
button = factory.createButton();
checkbox = factory.createCheckbox();
}
public void paint() {
button.paint();
checkbox.paint();
}
}
public class Demo {
/** * Application picks the factory type and creates it in run time (usually at * initialization stage), depending on the configuration or environment * variables. */
private static Application configureApplication() {
Application app;
GUIFactory factory;
String osName = System.getProperty("os.name").toLowerCase();
if (osName.contains("mac")) {
factory = new MacOSFactory();
app = new Application(factory);
} else {
factory = new WindowsFactory();
app = new Application(factory);
}
return app;
}
public static void main(String[] args) {
Application app = configureApplication();
app.paint();
}
}
生成器模式
使你能够分步骤创建复杂对象。 该模式允许你使用相同的创建代码生成不同类型和形式的对象。
建造一栋简单的房屋, 首先你需要建造四面墙和地板
, 安装房门和一套窗户
, 然后再建造一个屋顶
。 但是如果你想要一栋更宽敞更明亮的房屋
, 还要有院子和其他设施 (例如暖气、 排水和供电设备
), 那又该怎么办呢?
最简单的方法是扩展 房屋基类
, 然后创建一系列涵盖所有参数组合的子类
。 但最终你将面对相当数量的子类。 任何新增的参数 (例如门廊类型) 都会让这个层次结构更加复杂
。
另一种方法则无需生成子
类。 你可以在 房屋基类中创建一个包括所有可能参数的超级构造函数
, 并用它来控制房屋对象
。 这种方法确实可以避免生成子类, 但它却会造成另外一个问题
。 生成器模式建议将对象构造代码从产品类中抽取出来
, 并将其放在一个名为生成器的独立对象中
创建多个不同的生成器
, 用不同方式实现一组相同的创建步骤
。 然后你就可以在创建过程中使用这些生成器
(例如按顺序调用多个构造步骤
) 来生成不同类型的对象
。 第一个
建造者使用木头和玻璃
制造房屋, 第二个
建造者使用石头和钢铁
, 而第三个
建造者使用黄金和钻石
。 在调用同一组步骤后
, 第一个建造者会给你一栋普通房屋
, 第二个会给你一座小城堡
, 而第三个则会给你一座宫殿
你可以进一步将用于创建产品的一系列生成器步骤
调用抽取成为单独的主管类
。 主管类
可定义创建步骤的执行顺序
, 而生成器
则提供这些步骤的实现
目的
根据不同的属性需要,使用相同的步骤,创造拥有不同属性的对象
分步骤地 制造 不同型号的汽车, 使用 相同的生产过程 制造不同类型的产品 (汽车手册)
结构
场景
假设你的构造函数中有十个可选参数
, 那么调用该函数会非常不方便; 因此, 你需要重载这个构造函数, 新建几个只有较少参数的简化版
。 但这些构造函数仍需调用主构造函数, 传递一些默认数值
来替代省略掉的参数
class Pizza {
Pizza(int size) {
... }
Pizza(int size, boolean cheese) {
... }
Pizza(int size, boolean cheese, boolean pepperoni) {
... }
// ...
生成器模式让你可以分步骤生成对象
, 而且允许你仅使用必须的步骤
。 应用该模式后, 你再也不需要将几十个参数塞进构造函数里了
如果你需要创建的各种形式的产品
, 它们的制造过程相似
且仅有细节上的差异
, 此时可使用生成器模式。
基本生成器接口
中定义了所有可能的制造步骤
, 具体生成器
将实现这些步骤
来制造特定形式的产品。 同时, 主管类
将负责管理制造步骤的顺序
优缺点
可以 分步创建 对象, 暂缓创建步骤 或 递归运行创建步骤。
生成 不同形式的产品 时, 可以 复用相同 的 制造代码。
单一职责 原则。 可以将 复杂构造代码 从 产品的 业务逻辑 中分离出来。
由于该模式需要新增多个类, 因此 代码 整体复杂程度 会有所增加
示例代码
主管 控制着 构造顺序。 它知道 制造 各种汽车型号 需要 调用 的 生产步骤
它仅与 汽车的 通用接口进行交互。 这样就能 将不同类型的生成器 传递给主管了
最终结果 将 从生成器对象中 获得, 因为 主管 不知道 最终产品的类型
只有 生成器对象知道 自己生成的产品 是什么
builders
public interface Builder {
void setCarType(CarType type);
void setEngine(Engine engine);
void setTripComputer(TripComputer tripComputer);
void setGPSNavigator(GPSNavigator gpsNavigator);
}
public class CarBuilder implements Builder {
private CarType type;
private Engine engine;
private TripComputer tripComputer;
private GPSNavigator gpsNavigator;
@Override
public void setCarType(CarType type) {
this.type = type;
}
...
public Car getResult() {
return new Car(type, seats, engine, transmission, tripComputer, gpsNavigator);
}
}
public class CarManualBuilder implements Builder{
private CarType type;
private Engine engine;
private TripComputer tripComputer;
private GPSNavigator gpsNavigator;
@Override
public void setCarType(CarType type) {
this.type = type;
}
...
public Manual getResult() {
return new Manual(type, seats, engine, transmission, tripComputer, gpsNavigator);
}
}
cars
public class Car {
private final CarType carType;
private final Engine engine;
private final TripComputer tripComputer;
private final GPSNavigator gpsNavigator;
private double fuel = 0;
public Car(CarType carType, Engine engine, TripComputer tripComputer, GPSNavigator gpsNavigator) {
this.carType = carType;
this.engine = engine;
this.tripComputer = tripComputer;
if (this.tripComputer != null) {
this.tripComputer.setCar(this);
}
this.gpsNavigator = gpsNavigator;
}
public CarType getCarType() {
return carType;
}
...
}
public class Manual {
private final CarType carType;
private final Engine engine;
private final TripComputer tripComputer;
private final GPSNavigator gpsNavigator;
public Ma