结构型模式主要关注类或对象的组合,旨在通过识别简单的结构关系来设计更复杂的结构。以下是几种常见的结构型设计模式:
1. 适配器模式(Adapter Pattern)
-
- 将一个类的接口转换成客户端所期望的另一个接口,使得原本由于接口不兼容而不能一起工作的那些类可以一起工作。
- 适用于需要使用现有类但其接口不符合需求的情况。
假设我们有一个旧的MediaPlayer
接口,它只能播放.mp3
文件。现在我们需要一个新功能,能够播放.wav
格式的文件。我们可以使用适配器模式来解决这个问题。
// 已有的MediaPlayer接口
interface MediaPlayer {void play(String audioType, String fileName);
}// 实现了MediaPlayer接口的类
class AudioPlayer implements MediaPlayer {@Overridepublic void play(String audioType, String fileName) {if (audioType.equalsIgnoreCase("mp3")) {System.out.println("Playing mp3 file. Name: " + fileName);} else {System.out.println("Invalid media. " + audioType + " format not supported");}}
}// 新的AdvancedMediaPlayer接口及其实现类
interface AdvancedMediaPlayer {void playWav(String fileName);
}class WavPlayer implements AdvancedMediaPlayer {@Overridepublic void playWav(String fileName) {System.out.println("Playing wav file. Name: " + fileName);}
}// 创建适配器类
class MediaAdapter implements MediaPlayer {private AdvancedMediaPlayer advancedMusicPlayer;public MediaAdapter() {advancedMusicPlayer = new WavPlayer();}@Overridepublic void play(String audioType, String fileName) {if(audioType.equalsIgnoreCase("wav")) {advancedMusicPlayer.playWav(fileName);}}
}// 使用适配器
public class AdapterPatternDemo {public static void main(String[] args) {MediaPlayer audioPlayer = new AudioPlayer();audioPlayer.play("mp3", "song.mp3");audioPlayer.play("wav", "song.wav"); // 这里会显示不支持MediaPlayer mediaAdapter = new MediaAdapter();mediaAdapter.play("wav", "song.wav"); // 现在可以播放wav文件}
}
2. 桥接模式(Bridge Pattern)
-
- 将抽象部分与它的实现部分分离,使它们都可以独立变化。
- 适用于当不想在抽象和实现之间建立固定的绑定关系时,例如图形库中形状和颜色的组合。
假设我们有一个绘图应用程序,它可以绘制不同形状,并且这些形状可以用不同的颜色绘制。为了使形状和颜色独立变化,我们可以使用桥接模式。
// 颜色接口
interface Color {void applyColor();
}// 具体的颜色实现
class RedColor implements Color {@Overridepublic void applyColor() {System.out.println("Red color applied.");}
}class BlueColor implements Color {@Overridepublic void applyColor() {System.out.println("Blue color applied.");}
}// 抽象的形状类,持有Color对象的引用
abstract class Shape {protected Color color;public Shape(Color color) {this.color = color;}abstract void draw();
}// 具体的形状实现
class Circle extends Shape {public Circle(Color color) {super(color);}@Overridevoid draw() {System.out.print("Drawing Circle. ");color.applyColor();}
}// 使用桥接模式
public class BridgePatternDemo {public static void main(String[] args) {Shape redCircle = new Circle(new RedColor());redCircle.draw(); // 输出:Drawing Circle. Red color applied.Shape blueCircle = new Circle(new BlueColor());blueCircle.draw(); // 输出:Drawing Circle. Blue color applied.}
}
3. 组合模式(Composite Pattern)
-
- 允许将对象组合成树形结构以表示“部分-整体”的层次结构,使得用户对单个对象和组合对象的使用具有一致性。
- 常用于文件系统、菜单等层次化结构的场景。
假设我们有一个组织结构,包括员工和部门。每个部门可能包含多个员工和其他部门。我们可以使用组合模式来处理这种“部分-整体”的层次结构。
// 组件接口
interface Employee {void showEmployeeDetails();
}// 叶子节点
class Developer implements Employee {private String name;private long empId;public Developer(String name, long empId) {this.name = name;this.empId = empId;}@Overridepublic void showEmployeeDetails() {System.out.println("Developer Name: " + name + ", EmpId: " + empId);}
}// 组合部件
class Manager implements Employee {private List<Employee> employees = new ArrayList<>();public void addEmployee(Employee emp) {employees.add(emp);}public void removeEmployee(Employee emp) {employees.remove(emp);}@Overridepublic void showEmployeeDetails() {for (Employee emp : employees) {emp.showEmployeeDetails();}}
}// 使用组合模式
public class CompositePatternDemo {public static void main(String[] args) {Employee dev1 = new Developer("John", 1001L);Employee dev2 = new Developer("Jane", 1002L);Manager manager = new Manager();manager.addEmployee(dev1);manager.addEmployee(dev2);Employee dev3 = new Developer("Doe", 1003L);manager.addEmployee(dev3);manager.showEmployeeDetails();}
}
4. 装饰模式(Decorator Pattern)
-
- 动态地给一个对象添加一些额外的职责,就增加功能来说,比生成子类更为灵活。
- 适用于需要动态地为对象添加功能而不改变原有代码的情况,如Java中的I/O流。
装饰模式允许你通过创建一个包装对象动态地向一个对象添加功能,而不需要修改其结构。
// 基础组件接口
interface Coffee {double getCost(); // 获取成本String getDescription(); // 获取描述
}// 具体组件实现
class SimpleCoffee implements Coffee {@Overridepublic double getCost() { return 10; } // 简单咖啡的成本@Overridepublic String getDescription() { return "Simple Coffee"; }
}// 装饰器抽象类
abstract class CoffeeDecorator implements Coffee {protected Coffee decoratedCoffee;public CoffeeDecorator(Coffee c) {this.decoratedCoffee = c;}@Overridepublic double getCost() { return decoratedCoffee.getCost(); }@Overridepublic String getDescription() { return decoratedCoffee.getDescription(); }
}// 牛奶装饰器
class MilkDecorator extends CoffeeDecorator {public MilkDecorator(Coffee c) { super(c); }@Overridepublic double getCost() { return super.getCost() + 2; }@Overridepublic String getDescription() { return super.getDescription() + ", Milk"; }
}// 使用装饰模式
public class DecoratorPatternDemo {public static void main(String[] args) {Coffee myCoffee = new MilkDecorator(new SimpleCoffee());System.out.println("Cost: " + myCoffee.getCost());System.out.println("Description: " + myCoffee.getDescription());}
}
5. 外观模式(Facade Pattern)
-
- 为子系统中的一组接口提供一个一致的界面,定义了一个高层接口,这个接口使得这一子系统更加容易使用。
- 适用于简化复杂系统的接口,如数据库连接管理。
外观模式提供了一个统一的接口,用来访问子系统中的一群接口。它提供了一个高层次的接口,使得子系统更易于使用。
// 子系统类
class CPU {public void processData() { System.out.println("Processing data."); }
}class Memory {public void load() { System.out.println("Loading data from memory."); }
}class HardDrive {public void readData() { System.out.println("Reading data from hard drive."); }
}// 外观类
class ComputerFacade {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 startComputer() {memory.load();hardDrive.readData();cpu.processData();}
}// 使用外观模式
public class FacadePatternDemo {public static void main(String[] args) {ComputerFacade computer = new ComputerFacade();computer.startComputer();}
}
6. 享元模式(Flyweight Pattern)
-
- 运用共享技术有效地支持大量细粒度的对象。
- 适用于需要创建大量相似对象且内存占用成为问题的情况,如文本编辑器中的字符对象。
享元模式主要用于减少创建对象的数量,以减少内存占用和提高性能。它通过共享尽可能多的对象来做到这一点。
// 享元接口
interface Shape {void draw(String color);
}// 具体享元类
class Circle implements Shape {private String color;public Circle(String color) {this.color = color;}@Overridepublic void draw(String fillColor) {System.out.println("Drawing Circle [Color: " + color + ", FillColor: " + fillColor + "]");}
}// 享元工厂
class ShapeFactory {private static final HashMap<String, Shape> circleMap = new HashMap<>();public static Shape getCircle(String color) {Circle circle = (Circle)circleMap.get(color);if(circle == null) {circle = new Circle(color);circleMap.put(color, circle);System.out.println("Creating circle of color: " + color);}return circle;}
}// 使用享元模式
public class FlyweightPatternDemo {public static void main(String[] args) {ShapeFactory shapeFactory = new ShapeFactory();Shape shape1 = shapeFactory.getCircle("Red");shape1.draw("Dark Red");Shape shape2 = shapeFactory.getCircle("Red"); // 不会创建新对象shape2.draw("Light Red");}
}
7. 代理模式(Proxy Pattern)
-
- 为其他对象提供一种代理以控制对这个对象的访问。
- 适用于需要在访问对象时加入额外处理逻辑的情况,如远程调用、权限检查等。
代理模式为其他对象提供一种代理以控制对这个对象的访问。
// 主题接口
interface Image {void display();
}// 真实主题类
class RealImage implements Image {private String fileName;public RealImage(String fileName) {this.fileName = fileName;loadFromDisk(fileName);}@Overridepublic void display() {System.out.println("Displaying " + fileName);}private void loadFromDisk(String fileName) {System.out.println("Loading " + 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 ProxyPatternDemo {public static void main(String[] args) {Image image = new ProxyImage("test_10mb.jpg");// 图像将从磁盘加载image.display();System.out.println("");// 图像不会从磁盘加载image.display();}
}