最近和字节3-1的大佬交流,他分享了一些字节跳动代码架构设计理念,接下来用故事化的角度阐述。
面试官: 你好,今天我们要讨论的是享元模式。首先,你能解释一下什么是享元模式吗?
求职者: 当然可以。享元模式是一种结构型设计模式,它主要用于减少创建对象的数量,以减少内存占用和提高性能。这种模式强调了在多个对象间尽可能共享数据来减少资源消耗。它把对象的信息分为两个部分:内在状态和外在状态。内在状态是存储在享元内部的信息,它可以被多个上下文共享;外在状态是随着上下文变化而变化的,不能共享的状态。
面试官: 很好。那么在实际应用中,享元模式有哪些用途呢?
求职者: 享元模式在需要大量相似对象时非常有用,例如在游戏中的粒子系统、图形软件中的线条和字符渲染,或者在数据库连接池和线程池中。所有这些场景中,通过共享对象来减少内存的使用都是非常重要的。
面试官: 对,这些都是享元模式的典型应用场景。那么,你能用代码示例说明一下享元模式是怎样实现的吗?
求职者: 当然可以。以围棋游戏为例,我们可以创建一个棋子工厂,它只生成两种颜色的棋子对象,其他的棋子都是这两个对象的引用。这里是一个简单的代码实现:
import java.util.HashMap; import java.util.Map; enum Color { BLACK, WHITE } class Piece { private final Color color; public Piece(Color color) { this.color = color; } // Getters and other methods } class PieceFactory { private Map<Color, Piece> pieces = new HashMap<>(); public Piece getPiece(Color color) { if (!pieces.containsKey(color)) { pieces.put(color, new Piece(color)); } return pieces.get(color); } } public class FlyweightPatternDemo { public static void main(String[] args) { PieceFactory factory = new PieceFactory(); Piece black1 = factory.getPiece(Color.BLACK); Piece white1 = factory.getPiece(Color.WHITE); Piece black2 = factory.getPiece(Color.BLACK); // Here black1 and black2 are references to the same object } }
在这个例子中,即使有多次对黑色或白色棋子的请求,工厂类只创建了一个对象,其他的请求都返回了对这个对象的引用。
面试官: 非常好,你的解释非常清晰。那么,享元模式有哪些优点和可能的缺点呢?
求职者: 享元模式的优点是能大幅度减少系统中的对象数量,减少系统的内存使用,提高效率。但是,它的缺点可能包括复杂化对象的定义,因为它引入了外部状态和内部状态的概念。此外,如果过度使用,可能会导致代码难以理解和维护。
面试官: 很好,你的总结很到位。这就是我们今天要讨论的全部内容,谢谢你面试官: 很好,现在我们来深入讨论享元模式的一个关键概念。你能解释一下什么是内在状态和外在状态吗?
求职者: 当然可以。在享元模式中,内在状态,也就是内部状态,是存储在享元对象内部,并且不会随环境的改变而有所不同的信息。这部分信息是可以共享的。比如在围棋游戏中,棋子的颜色就是一个内在状态,因为不同的棋子可以共享同一种颜色。
相反,外在状态,也就是外部状态,是随环境改变而改变的状态,它不能被共享。在围棋游戏中,棋子的位置就是一个外在状态,因为每个棋子的位置都是独一无二的。
面试官: 非常好。那么,你能给出一个代码示例来进一步说明这两种状态吗?
求职者: 当然。继续使用围棋的例子,我们可以这样表示棋子的内在状态和外在状态:
class Piece { private final Color color; // 内在状态 public Piece(Color color) { this.color = color; } // Getter for color } class PieceBoard { private final Map<Piece, Position> piecePositions = new HashMap<>(); // 外在状态 public void placePiece(Piece piece, Position position) { piecePositions.put(piece, position); } // Other methods }
在这个例子中,Piece
类有一个颜色属性,它是内在状态。而PieceBoard
类管理了棋子的位置,这些位置是外在状态,因为它们会随着游戏的进行而变化。
面试官: 很好,你的解释非常清晰。这就是我们今天要讨论的全部内容,谢谢你的参与。