结构型设计模式(三)享元模式 & 代理模式 & 桥接模式

结构型设计模式(三)享元模式 & 代理模式 & 桥接模式_第1张图片

享元模式 Flyweight

1、什么是享元模式

享元模式的核心思想是共享对象,即通过尽可能多地共享相似对象来减少内存占用或计算开销。这意味着相同或相似的对象在内存中只存在一个共享实例。

2、为什么使用享元模式

  1. 减少内存使用:通过共享相似对象,减少了系统中对象的数量,从而减少了内存的使用。
  2. 提高性能:由于共享对象减少了创建和销毁的开销,提高了系统的性能。
  3. 简化代码:享元模式使得系统中的对象更加简单,因为需要相似的对象可以共享相同的状态。

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;
    }

    @Override
    public void display() {
        System.out.print(character);
    }
}

// 享元工厂
class CharFlyweightFactory {
    private Map 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();  // 输出:a
        b.display();  // 输出:b
        aAgain.display();  // 输出:a

        // 对比对象是否相同
        System.out.println("\nIs a the same object as aAgain? " + (a == aAgain));
    }
}

4、是否存在缺陷和不足

  1. 共享状态限制:享元模式主要适用于具有大量相似对象的情况,且这些对象可以共享状态。如果对象的状态不可共享,则不适合使用享元模式。
  2. 复杂性增加:在一些场景下,为了实现共享,需要将对象的一部分状态外部话,导致系统的复杂性增加。

5、如何缓解缺陷和不足

  1. 外部状态和内部状态分离:尽量将对象的外部状态(不可共享的状态)和内部状态(可共享的状态)清晰地分离,以便在不同的环境中使用。
  2. 合理使用享元模式:只有在系统中存在大量相似对象且能够共享状态时,才考虑使用享元模式,在其他情况下,可能并不切实际。

代理模式 Proxy

1、什么是代理模式

代理模式通过引入代理对象来控制对其他对象的访问。代理对象充当被代理对象的接口,可以在访问的时候添加额外的功能,比如安全性检查、缓存引入等操作功能。

2、为什么使用代理模式

  1. 控制访问:代理模式允许在访问对象时进行控制,可以添加额外的逻辑,比如权限检查、缓存引入等。
  2. 解耦:代理模式将客户端与目标对象解耦,客户端无需直接访问目标对象,降低了系统的耦合度。
  3. 延迟加载:代理模式可以实现延迟加载,在需要的时候再创建目标对象,提高系统的性能。

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);
    }

    @Override
    public 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;
    }

    @Override
    public 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、是否存在缺陷和不足

  1. 复杂性增加:引入代理对象可能会增加系统的复杂性,因为需要额外的类来管理代理和目标对象。
  2. 性能开销:在某些情况下,代理模式可能引入一定的性能开销,尤其是在代理对象的创建和销毁方面。

5、如何缓解缺陷和不足

  1. 智能代理:使用智能代理,根据具体情况选择是否创建目标对象,什么时候需要什么时候创建。
  2. 动态代理:使用动态代理,通过反射机制动态创建代理对象,减少手动创建代理对象的复杂性。

桥接模式 Bridge

1、什么是桥接模式

桥接模式的核心思想是将抽象部分和实现部分分离,使它们可以独立地发生变化。通过抽象类和实现类设计为两个独立的层次方案,并使用组合组合关系将他们连接起来。

2、为什么使用桥接模式

  1. 解耦抽象和实现:桥接模式将抽象和实现分离,使得他们可以独立地发生变化,降低系统的耦合度。
  2. 提高灵活性:桥接模式提高了系统的灵活性,可以更容易地添加新的抽象类和实现类。
  3. 复用性:可以在不修改已有代码的情况下引入新的抽象和实现。

3、如何使用桥接模式

设计实现一个图形绘制的场景,有不同类型的图形和不同的绘制方式,要求通过桥接模式将图形和绘制方式解耦。

// 实现部分 - 绘制方式
interface DrawingAPI {
    void drawCircle(int x, int y, int radius);
}

// 具体实现部分 - 红色绘制方式
class RedDrawingAPI implements DrawingAPI {
    @Override
    public void drawCircle(int x, int y, int radius) {
        System.out.println("Drawing Red Circle at (" + x + "," + y + ") with radius " + radius);
    }
}

// 具体实现部分 - 绿色绘制方式
class GreenDrawingAPI implements DrawingAPI {
    @Override
    public 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;
    }

    @Override
    void 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、是否存在缺陷和不足

  1. 增加复杂性:桥接模式可能会增加系统的复杂性,因为需要设计多个抽象类和实现的类层次结构。

5、如何缓解缺陷和不足

  1. 谨慎设计类的层次结构:设计抽象和实现的类层次结构时,需要谨慎考虑,避免过度设计。
  2. 使用合适的模式:根据系统的需求,考虑其他结构型模式,选择最适合的模式。

你可能感兴趣的:(设计模式,享元模式,代理模式,桥接模式)