设计模式——结构型模式
目录
适配器模式
装饰器模式
代理模式
外观模式
桥接模式
适配器模式
意图:将一个类的接口转换成客户端期望的另一个接口
适用场景:
想使用一个已存在的类,而它的接口不符合要求
想创建一个可以复用的类,该类可以与其他不相关的类或不可预见的类协同工作
示例
// 目标接口
interface MediaPlayer {void play(String audioType, String fileName);
}// 被适配者
interface AdvancedMediaPlayer {void playVlc(String fileName);void playMp4(String fileName);
}// 具体被适配者
class VlcPlayer implements AdvancedMediaPlayer {@Overridepublic void playVlc(String fileName) {System.out.println("播放VLC文件: " + fileName);}@Overridepublic void playMp4(String fileName) {// 什么也不做}
}class Mp4Player implements AdvancedMediaPlayer {@Overridepublic void playVlc(String fileName) {// 什么也不做}@Overridepublic void playMp4(String fileName) {System.out.println("播放MP4文件: " + fileName);}
}// 适配器
class MediaAdapter implements MediaPlayer {private AdvancedMediaPlayer advancedMusicPlayer;public MediaAdapter(String audioType) {if (audioType.equalsIgnoreCase("vlc")) {advancedMusicPlayer = new VlcPlayer();} else if (audioType.equalsIgnoreCase("mp4")) {advancedMusicPlayer = new Mp4Player();}}@Overridepublic void play(String audioType, String fileName) {if (audioType.equalsIgnoreCase("vlc")) {advancedMusicPlayer.playVlc(fileName);} else if (audioType.equalsIgnoreCase("mp4")) {advancedMusicPlayer.playMp4(fileName);}}
}// 客户端
class AudioPlayer implements MediaPlayer {private MediaAdapter mediaAdapter;@Overridepublic void play(String audioType, String fileName) {// 内置支持MP3if (audioType.equalsIgnoreCase("mp3")) {System.out.println("播放MP3文件: " + fileName);} // 使用适配器支持其他格式else if (audioType.equalsIgnoreCase("vlc") || audioType.equalsIgnoreCase("mp4")) {mediaAdapter = new MediaAdapter(audioType);mediaAdapter.play(audioType, fileName);} else {System.out.println("无效的媒体格式: " + audioType);}}
}
装饰器模式
意图:动态地给一个对象添加一些额外的职责
适用场景:
在不影响其他对象的情况下,以动态、透明的方式给单个对象添加职责
处理那些可以撤销的职责
当不能采用子类化的方法进行扩展时
示例
// 组件接口
interface Shape {void draw();
}// 具体组件
class Circle implements Shape {@Overridepublic void draw() {System.out.println("绘制圆形");}
}class Rectangle implements Shape {@Overridepublic void draw() {System.out.println("绘制矩形");}
}// 抽象装饰器
abstract class ShapeDecorator implements Shape {protected Shape decoratedShape;public ShapeDecorator(Shape decoratedShape) {this.decoratedShape = decoratedShape;}public void draw() {decoratedShape.draw();}
}// 具体装饰器
class RedShapeDecorator extends ShapeDecorator {public RedShapeDecorator(Shape decoratedShape) {super(decoratedShape);}@Overridepublic void draw() {decoratedShape.draw();setRedBorder();}private void setRedBorder() {System.out.println("边框颜色: 红色");}
}// 客户端使用
public class DecoratorDemo {public static void main(String[] args) {Shape circle = new Circle();Shape redCircle = new RedShapeDecorator(new Circle());Shape redRectangle = new RedShapeDecorator(new Rectangle());System.out.println("普通圆形:");circle.draw();System.out.println("\n红色边框圆形:");redCircle.draw();System.out.println("\n红色边框矩形:");redRectangle.draw();}
}
代理模式
意图:为其他对象提供一种代理以控制对这个对象的访问
适用场景:
远程代理:为一个对象在不同的地址空间提供局部代表
虚拟代理:根据需要创建开销很大的对象
保护代理:控制对原始对象的访问
智能指引:在访问对象时执行一些附加操作
示例
// 主题接口
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("加载图片: " + fileName);}@Overridepublic void display() {System.out.println("显示图片: " + 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 ProxyDemo {public static void main(String[] args) {Image image = new ProxyImage("test.jpg");// 图片将从磁盘加载image.display();System.out.println("");// 图片不需要从磁盘加载image.display();}
}
外观模式
意图:为子系统中的一组接口提供一个一致的界面
适用场景:
要为一个复杂子系统提供一个简单接口时
客户端与抽象类的实现部分之间存在着很大的依赖性时
需要构建一个层次结构的子系统时
// 子系统类
class CPU {public void freeze() {System.out.println("CPU冻结");}public void jump(long position) {System.out.println("CPU跳转到位置: " + position);}public void execute() {System.out.println("CPU执行");}
}class Memory {public void load(long position, byte[] data) {System.out.println("内存加载数据到位置: " + position);}
}class HardDrive {public byte[] read(long lba, int size) {System.out.println("硬盘读取数据,LBA: " + lba + ", 大小: " + size);return new byte[size];}
}// 外观类
class ComputerFacade {private static final long BOOT_ADDRESS = 0x0000;private static final long BOOT_SECTOR = 0x0000;private static final int SECTOR_SIZE = 1024;private CPU cpu;private Memory memory;private HardDrive hardDrive;public ComputerFacade() {this.cpu = new CPU();this.memory = new Memory();this.hardDrive = new HardDrive();}public void start() {System.out.println("计算机启动中...");cpu.freeze();memory.load(BOOT_ADDRESS, hardDrive.read(BOOT_SECTOR, SECTOR_SIZE));cpu.jump(BOOT_ADDRESS);cpu.execute();System.out.println("计算机启动完成");}
}// 客户端使用
public class FacadeDemo {public static void main(String[] args) {ComputerFacade computer = new ComputerFacade();computer.start();}
}
桥接模式
意图:将抽象部分与它的实现部分分离,使它们都可以独立地变化
适用场景:
不希望在抽象和它的实现部分之间有一个固定的绑定关系
类的抽象以及它的实现都应该可以通过子类化加以扩展
对一个抽象的实现部分的修改应对客户不产生影响
// 实现接口
interface DrawingAPI {void drawCircle(double x, double y, double radius);
}// 具体实现A
class DrawingAPI1 implements DrawingAPI {@Overridepublic void drawCircle(double x, double y, double radius) {System.out.printf("API1绘制圆 at %.2f:%.2f 半径 %.2f%n", x, y, radius);}
}// 具体实现B
class DrawingAPI2 implements DrawingAPI {@Overridepublic void drawCircle(double x, double y, double radius) {System.out.printf("API2绘制圆 at %.2f:%.2f 半径 %.2f%n", x, y, radius);}
}// 抽象
abstract class Shape {protected DrawingAPI drawingAPI;protected Shape(DrawingAPI drawingAPI) {this.drawingAPI = drawingAPI;}public abstract void draw();public abstract void resizeByPercentage(double pct);
}// 精确抽象
class CircleShape extends Shape {private double x, y, radius;public CircleShape(double x, double y, double radius, DrawingAPI drawingAPI) {super(drawingAPI);this.x = x;this.y = y;this.radius = radius;}@Overridepublic void draw() {drawingAPI.drawCircle(x, y, radius);}@Overridepublic void resizeByPercentage(double pct) {radius *= (1.0 + pct / 100.0);}
}// 客户端使用
public class BridgeDemo {public static void main(String[] args) {Shape[] shapes = new Shape[] {new CircleShape(1, 2, 3, new DrawingAPI1()),new CircleShape(5, 7, 11, new DrawingAPI2())};for (Shape shape : shapes) {shape.resizeByPercentage(2.5);shape.draw();}}
}
