聊一聊设计模式(三)

109 阅读3分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 2 月更文挑战」的第 22 天,点击查看活动详情

每日英语:

Concision in style,precision in thought,decision in life.

文体要简洁,思想要严谨,生活要果断。 -维克多·雨果

除了上一篇介绍的装饰者模式、模板方法模式、策略模式,还有很多其他常用的设计模式。在这里,我将介绍几种常见的设计模式,并提供相应的Java代码案例。

代理模式

代理模式(Proxy Pattern)为其他对象提供一种代理以控制对这个对象的访问。它是一种结构型设计模式,它可以为其他对象提供一个代理对象,以控制对原始对象的访问。以下是一个Java代码示例:

public interface Image {
    void display();
}

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

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

在上面的代码中,Image是一个接口,它定义了一个显示图像的方法。RealImage是一个具体的图像实现类,它实现了Image接口,并定义了加载图像文件的方法。ProxyImage是一个代理类,它也实现了Image接口,并持有一个RealImage对象的引用。在ProxyImagedisplay方法中,如果RealImage对象尚未创建,则它将创建一个并显示它。

适配器模式

适配器模式(Adapter Pattern)将一个类的接口转换成客户端所期望的另一种接口,从而使得原本不兼容的接口可以协同工作。

以下是一个Java代码示例:

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: " + fileName);
    }
    
    @Override
    public void playMp4(String fileName) {
        // do nothing
    }
}

public class Mp4Player implements AdvancedMediaPlayer {
    @Override
    public void playVlc(String fileName) {
        // do nothing
    }
    
    @Override
    public void playMp4(String fileName) {
        System.out.println("Playing MP4 file: " + fileName);
    }
}

public class MediaAdapter implements MediaPlayer {
    private AdvancedMediaPlayer player;
    
    public MediaAdapter(String audioType) {
        if (audioType.equalsIgnoreCase("vlc")) {
            player = new VlcPlayer();
        } else if (audioType.equalsIgnoreCase("mp4")) {
            player = new Mp4Player();
        }
    }
    
    @Override
    public void play(String audioType, String fileName) {
        if (audioType.equalsIgnoreCase("vlc")) {
            player.playVlc(fileName);
        } else if (audioType.equalsIgnoreCase("mp4")) {
            player.playMp4(fileName);
        }
    }
}

public class AudioPlayer implements MediaPlayer {
    private MediaAdapter mediaAdapter;
    
    @Override
    public void play(String audioType, String fileName) {
        if (audioType.equalsIgnoreCase("mp3")) {
            System.out.println("Playing MP3 file: " + fileName);
        } else if (audioType.equalsIgnoreCase("vlc") || audioType.equalsIgnoreCase("mp4")) {
            mediaAdapter = new MediaAdapter(audioType);
            mediaAdapter.play(audioType, fileName);
        } else {
            System.out.println("Invalid media type: " + audioType);
        }
    }
}

public class Client {
    public static void main(String[] args) {
        AudioPlayer player = new AudioPlayer();
        player.play("mp3", "song.mp3");
        player.play("vlc", "movie.vlc");
        player.play("mp4", "video.mp4");
        player.play("avi", "movie.avi");
    }
}

在上面的代码中,MediaPlayer是一个接口,它定义了一个play()方法,用于播放媒体文件。AdvancedMediaPlayer是另一个接口,它定义了playVlc()playMp4()方法,用于播放VLC和MP4格式的媒体文件。

VlcPlayerMp4Player是具体的媒体播放器实现类,它们实现了AdvancedMediaPlayer接口,并分别实现了播放VLC和MP4格式的媒体文件的方法。

MediaAdapter是一个适配器类,它实现了MediaPlayer接口,并持有一个AdvancedMediaPlayer实例。

原型模式

原型模式(Prototype Pattern)是用于创建重复的对象,同时又能保持性能的设计模式。通过复制已有对象的数据来创建新对象,而不是使用实例化过程。

以下是一个Java代码示例:

public abstract class Shape implements Cloneable {
    private String id;
    protected String type;
    
    public String getId() {
        return id;
    }
    
    public String getType() {
        return type;
    }
    
    public void setId(String id) {
        this.id = id;
    }
    
    public abstract void draw();
    
    @Override
    public Object clone() {
        Object clone = null;
        
        try {
            clone = super.clone();
        } catch (CloneNotSupportedException e) {
            e.printStackTrace();
        }
        
        return clone;
    }
}

public class Circle extends Shape {
    public Circle() {
        type = "Circle";
    }
    
    @Override
    public void draw() {
        System.out.println("Drawing a circle.");
    }
}

public class Square extends Shape {
    public Square() {
        type = "Square";
    }
    
    @Override
    public void draw() {
        System.out.println("Drawing a square.");
    }
}

public class ShapeCache {
    private static Map<String, Shape> shapeMap = new HashMap<>();
    
    public static Shape getShape(String shapeId) {
        Shape cachedShape = shapeMap.get(shapeId);
        return (Shape) cachedShape.clone();
    }
    
    public static void loadCache() {
        Circle circle = new Circle();
        circle.setId("1");
        shapeMap.put(circle.getId(), circle);
        
        Square square = new Square();
        square.setId("2");
        shapeMap.put(square.getId(), square);
    }
}

public class Client {
    public static void main(String[] args) {
        ShapeCache.loadCache();
        
        Shape clonedShape1 = ShapeCache.getShape("1");
        System.out.println("Shape: " + clonedShape1.getType());
        
        Shape clonedShape2 = ShapeCache.getShape("2");
        System.out.println("Shape: " + clonedShape2.getType());
    }
}

总结

本篇主要讲了一下代理模式、适配器模式、原型模式这三种,并给了对应的代码示例,有兴趣的小伙伴可以拿来跑跑,学习学习。