享元模式 Flyweight
1、什么是享元模式
享元模式的核心思想是共享对象,即通过尽可能多地共享相似对象来减少内存占用或计算开销。这意味着相同或相似的对象在内存中只存在一个共享实例。
2、为什么使用享元模式
- 减少内存使用:通过共享相似对象,减少了系统中对象的数量,从而减少了内存的使用。
- 提高性能:由于共享对象减少了创建和销毁的开销,提高了系统的性能。
- 简化代码:享元模式使得系统中的对象更加简单,因为需要相似的对象可以共享相同的状态。
3、如何使用享元模式
设计和实现一个文本编辑器,针对大量相似的字符对象,通过享元模式来共享相同字符对象
import java.util.HashMap;
import java.util.Map;// 抽象享元角色
interface CharFlyweight {void display();
}// 具体享元角色
class ConcreteCharFlyweight implements CharFlyweight {private char character;public ConcreteCharFlyweight(char character) {this.character = character;}@Overridepublic void display() {System.out.print(character);}
}// 享元工厂
class CharFlyweightFactory {private Map<Character, CharFlyweight> flyweights = new HashMap<>();public CharFlyweight getCharFlyweight(char character) {if (!flyweights.containsKey(character)) {flyweights.put(character, new ConcreteCharFlyweight(character));}return flyweights.get(character);}
}// 客户端代码
public class Client {public static void main(String[] args) {CharFlyweightFactory factory = new CharFlyweightFactory();CharFlyweight a = factory.getCharFlyweight('a');CharFlyweight b = factory.getCharFlyweight('b');CharFlyweight aAgain = factory.getCharFlyweight('a');a.display(); // 输出:ab.display(); // 输出:baAgain.display(); // 输出:a// 对比对象是否相同System.out.println("\nIs a the same object as aAgain? " + (a == aAgain));}
}
4、是否存在缺陷和不足
- 共享状态限制:享元模式主要适用于具有大量相似对象的情况,且这些对象可以共享状态。如果对象的状态不可共享,则不适合使用享元模式。
- 复杂性增加:在一些场景下,为了实现共享,需要将对象的一部分状态外部话,导致系统的复杂性增加。
5、如何缓解缺陷和不足
- 外部状态和内部状态分离:尽量将对象的外部状态(不可共享的状态)和内部状态(可共享的状态)清晰地分离,以便在不同的环境中使用。
- 合理使用享元模式:只有在系统中存在大量相似对象且能够共享状态时,才考虑使用享元模式,在其他情况下,可能并不切实际。
代理模式 Proxy
1、什么是代理模式
代理模式通过引入代理对象来控制对其他对象的访问。代理对象充当被代理对象的接口,可以在访问的时候添加额外的功能,比如安全性检查、缓存引入等操作功能。
2、为什么使用代理模式
- 控制访问:代理模式允许在访问对象时进行控制,可以添加额外的逻辑,比如权限检查、缓存引入等。
- 解耦:代理模式将客户端与目标对象解耦,客户端无需直接访问目标对象,降低了系统的耦合度。
- 延迟加载:代理模式可以实现延迟加载,在需要的时候再创建目标对象,提高系统的性能。
3、如何使用代理模式
设计实现一个 Image 接口,具体的实现类是 RealImage。通过代理模式,因为 ProxyImage 来控制对 RealImage 的访问
// 目标接口
interface Image {void display();
}// 具体目标类
class RealImage implements Image {private String filename;public RealImage(String filename) {this.filename = filename;loadFromDisk();}private void loadFromDisk() {System.out.println("Loading image: " + filename);}@Overridepublic void display() {System.out.println("Displaying image: " + filename);}
}// 代理类
class ProxyImage implements Image {private RealImage realImage;private String filename;public ProxyImage(String filename) {this.filename = filename;}@Overridepublic void display() {if (realImage == null) {realImage = new RealImage(filename);}realImage.display();}
}// 客户端代码
public class Client {public static void main(String[] args) {Image image = new ProxyImage("example.jpg");// 图像第一次加载image.display();// 图像第二次加载,使用缓存image.display();}
}
4、是否存在缺陷和不足
- 复杂性增加:引入代理对象可能会增加系统的复杂性,因为需要额外的类来管理代理和目标对象。
- 性能开销:在某些情况下,代理模式可能引入一定的性能开销,尤其是在代理对象的创建和销毁方面。
5、如何缓解缺陷和不足
- 智能代理:使用智能代理,根据具体情况选择是否创建目标对象,什么时候需要什么时候创建。
- 动态代理:使用动态代理,通过反射机制动态创建代理对象,减少手动创建代理对象的复杂性。
桥接模式 Bridge
1、什么是桥接模式
桥接模式的核心思想是将抽象部分和实现部分分离,使它们可以独立地发生变化。通过抽象类和实现类设计为两个独立的层次方案,并使用组合组合关系将他们连接起来。
2、为什么使用桥接模式
- 解耦抽象和实现:桥接模式将抽象和实现分离,使得他们可以独立地发生变化,降低系统的耦合度。
- 提高灵活性:桥接模式提高了系统的灵活性,可以更容易地添加新的抽象类和实现类。
- 复用性:可以在不修改已有代码的情况下引入新的抽象和实现。
3、如何使用桥接模式
设计实现一个图形绘制的场景,有不同类型的图形和不同的绘制方式,要求通过桥接模式将图形和绘制方式解耦。
// 实现部分 - 绘制方式
interface DrawingAPI {void drawCircle(int x, int y, int radius);
}// 具体实现部分 - 红色绘制方式
class RedDrawingAPI implements DrawingAPI {@Overridepublic void drawCircle(int x, int y, int radius) {System.out.println("Drawing Red Circle at (" + x + "," + y + ") with radius " + radius);}
}// 具体实现部分 - 绿色绘制方式
class GreenDrawingAPI implements DrawingAPI {@Overridepublic void drawCircle(int x, int y, int radius) {System.out.println("Drawing Green Circle at (" + x + "," + y + ") with radius " + radius);}
}// 抽象部分 - 图形
abstract class Shape {protected DrawingAPI drawingAPI;protected Shape(DrawingAPI drawingAPI) {this.drawingAPI = drawingAPI;}abstract void draw();
}// 具体抽象部分 - 圆形
class Circle extends Shape {private int x, y, radius;public Circle(int x, int y, int radius, DrawingAPI drawingAPI) {super(drawingAPI);this.x = x;this.y = y;this.radius = radius;}@Overridevoid draw() {drawingAPI.drawCircle(x, y, radius);}
}// 客户端代码
public class Client {public static void main(String[] args) {DrawingAPI redAPI = new RedDrawingAPI();DrawingAPI greenAPI = new GreenDrawingAPI();Shape redCircle = new Circle(100, 100, 10, redAPI);Shape greenCircle = new Circle(200, 200, 20, greenAPI);redCircle.draw();greenCircle.draw();}
}
4、是否存在缺陷和不足
- 增加复杂性:桥接模式可能会增加系统的复杂性,因为需要设计多个抽象类和实现的类层次结构。
5、如何缓解缺陷和不足
- 谨慎设计类的层次结构:设计抽象和实现的类层次结构时,需要谨慎考虑,避免过度设计。
- 使用合适的模式:根据系统的需求,考虑其他结构型模式,选择最适合的模式。