
结构型模式主要关注类或对象的组合,旨在通过识别简单的结构关系来设计更复杂的结构。以下是几种常见的结构型设计模式:
1. 适配器模式(Adapter Pattern)
-
- 将一个类的接口转换成客户端所期望的另一个接口,使得原本由于接口不兼容而不能一起工作的那些类可以一起工作。
- 适用于需要使用现有类但其接口不符合需求的情况。
假设我们有一个旧的MediaPlayer
接口,它只能播放.mp3
文件。现在我们需要一个新功能,能够播放.wav
格式的文件。我们可以使用适配器模式来解决这个问题。
// 已有的MediaPlayer接口
interface MediaPlayer {
void play(String audioType, String fileName);
}
// 实现了MediaPlayer接口的类
class AudioPlayer implements MediaPlayer {
@Override
public 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 {
@Override
public void playWav(String fileName) {
System.out.println("Playing wav file. Name: " + fileName);
}
}
// 创建适配器类
class MediaAdapter implements MediaPlayer {
private AdvancedMediaPlayer advancedMusicPlayer;
public MediaAdapter() {
advancedMusicPlayer = new WavPlayer();
}
@Override
public 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 {
@Override
public void applyColor() {
System.out.println("Red color applied.");
}
}
class BlueColor implements Color {
@Override
public 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);
}
@Override
void 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;
}
@Override
public 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);
}
@Override
public 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 {
@Override
public double getCost() { return 10; } // 简单咖啡的成本
@Override
public String getDescription() { return "Simple Coffee"; }
}
// 装饰器抽象类
abstract class CoffeeDecorator implements Coffee {
protected Coffee decoratedCoffee;
public CoffeeDecorator(Coffee c) {
this.decoratedCoffee = c;
}
@Override
public double getCost() { return decoratedCoffee.getCost(); }
@Override
public String getDescription() { return decoratedCoffee.getDescription(); }
}
// 牛奶装饰器
class MilkDecorator extends CoffeeDecorator {
public MilkDecorator(Coffee c) { super(c); }
@Override
public double getCost() { return super.getCost() + 2; }
@Override
public 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;
}
@Override
public 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);
}
@Override
public 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;
}
@Override
public 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();
}
}