结构型设计模式主要解决类和对象之间的组合关系。它关注如何通过不同的方式组合类和对象,使系统的结构更加灵活和高效。通过这些模式,我们可以优化代码结构,减少系统间的耦合性,增加代码的可维护性和可扩展性。
1. 适配器模式 (Adapter Pattern)
适配器模式的主要目的是将某个类的接口转化为客户端期望的接口,使得本来由于接口不兼容而不能一起工作的类可以协同工作。
实现方式
定义一个目标接口,客户端通过该接口与适配器交互。
创建一个适配器类,将源类的接口转换为目标接口。
Java实现
// 目标接口
interface MediaPlayer {
void play(String audioType, String fileName);
}
// 源类:VLC播放器
class VLCPlayer implements MediaPlayer {
public void play(String audioType, String fileName) {
System.out.println("Playing VLC file. Name: " + fileName);
}
}
// 适配器类:MediaAdapter
class MediaAdapter implements MediaPlayer {
private AdvancedMediaPlayer advancedMusicPlayer;
public MediaAdapter(String audioType) {
if(audioType.equalsIgnoreCase("mp4")){
advancedMusicPlayer = new MP4Player();
}
else if(audioType.equalsIgnoreCase("vlc")){
advancedMusicPlayer = new VLCPlayer();
}
}
public void play(String audioType, String fileName) {
if(audioType.equalsIgnoreCase("vlc")){
advancedMusicPlayer.playVlc(fileName);
}
else if(audioType.equalsIgnoreCase("mp4")){
advancedMusicPlayer.playMP4(fileName);
}
}
}
// 高级播放器接口
interface AdvancedMediaPlayer {
void playVlc(String fileName);
void playMP4(String fileName);
}
// 具体的高级播放器:MP4播放器
class MP4Player implements AdvancedMediaPlayer {
public void playVlc(String fileName) {
// 什么都不做
}
public void playMP4(String fileName) {
System.out.println("Playing MP4 file. Name: " + fileName);
}
}
public class AdapterDemo {
public static void main(String[] args) {
AudioPlayer audioPlayer = new AudioPlayer();
audioPlayer.play("mp4", "beyond the horizon.mp4");
audioPlayer.play("vlc", "far far away.vlc");
audioPlayer.play("avi", "mind me.avi");
}
}
AudioPlayer 充当客户端与适配器之间的连接角色,它只关心播放文件而不关心具体的播放器实现。
MediaAdapter 类将 VLC 和 MP4 播放器适配为统一的接口
MediaPlayer
2. 桥接模式 (Bridge Pattern)
桥接模式将抽象部分与实现部分分离,使得二者可以独立地变化。它将接口与实现的继承关系解耦,提高系统的灵活性。
实现方式
创建一个桥接接口,定义抽象部分的操作。
将实现部分封装到独立的类中,实现接口。
通过桥接接口,将抽象类与实现类进行关联。
Java实现
// 抽象部分
interface Shape {
void draw();
}
// 具体抽象类
class Circle implements Shape {
private Color color;
public Circle(Color color) {
this.color = color;
}
public void draw() {
System.out.print("Drawing a Circle, Color: ");
color.fill();
}
}
// 实现部分
interface Color {
void fill();
}
// 具体实现类:Red
class Red implements Color {
public void fill() {
System.out.println("Red");
}
}
// 具体实现类:Blue
class Blue implements Color {
public void fill() {
System.out.println("Blue");
}
}
public class BridgeDemo {
public static void main(String[] args) {
Shape redCircle = new Circle(new Red());
redCircle.draw(); // 输出: Drawing a Circle, Color: Red
Shape blueCircle = new Circle(new Blue());
blueCircle.draw(); // 输出: Drawing a Circle, Color: Blue
}
}
Shape 类与 Color 类通过桥接接口解耦。Circle 是一个抽象类,Red 和 Blue 是具体的实现类。
使用桥接模式,可以方便地将抽象部分与实现部分独立扩展。
3. 组合模式 (Composite Pattern)
组合模式使得客户端可以以一致的方式对待单个对象和对象集合。它将对象组合成树形结构来表示“部分-整体”层次结构,能够让客户端对单个对象和复合对象(容器)进行相同的处理。
实现方式
定义一个组件接口,声明所有对象的公共方法。
叶子节点类实现组件接口,表示单一对象。
容器节点类实现组件接口,包含多个叶子节点或者子节点。
Java实现
// 组件接口
interface Component {
void operation();
}
// 叶子节点类
class Leaf implements Component {
private String name;
public Leaf(String name) {
this.name = name;
}
public void operation() {
System.out.println("Leaf " + name + " operation.");
}
}
// 容器节点类
class Composite implements Component {
private List<Component> children = new ArrayList<>();
public void add(Component component) {
children.add(component);
}
public void remove(Component component) {
children.remove(component);
}
public void operation() {
for (Component component : children) {
component.operation();
}
}
}
public class CompositeDemo {
public static void main(String[] args) {
Composite root = new Composite();
Composite branch1 = new Composite();
Composite branch2 = new Composite();
Leaf leaf1 = new Leaf("Leaf1");
Leaf leaf2 = new Leaf("Leaf2");
root.add(branch1);
root.add(branch2);
branch1.add(leaf1);
branch2.add(leaf2);
root.operation();
}
}
Composite 类是一个容器,它包含多个 Component 对象,既可以是叶子节点,也可以是子容器节点。
客户端可以一致地操作单一叶子节点或包含多个叶子节点的容器。
4. 装饰器模式 (Decorator Pattern)
装饰器模式允许你动态地给一个对象添加额外的职责,而不影响其他对象。通过组合而非继承的方式,装饰器模式可以在运行时修改对象的行为。
实现方式
定义一个组件接口,表示被装饰的对象。
创建一个装饰器类,实现组件接口,并在其中添加额外功能。
Java实现
// 组件接口
interface Coffee {
double cost();
}
// 具体组件类
class SimpleCoffee implements Coffee {
public double cost() {
return 5;
}
}
// 装饰器基类
class CoffeeDecorator implements Coffee {
protected Coffee decoratedCoffee;
public CoffeeDecorator(Coffee coffee) {
this.decoratedCoffee = coffee;
}
public double cost() {
return decoratedCoffee.cost();
}
}
// 具体装饰器类:加糖
class WithSugar extends CoffeeDecorator {
public WithSugar(Coffee coffee) {
super(coffee);
}
public double cost() {
return super.cost() + 2;
}
}
// 具体装饰器类:加奶
class WithMilk extends CoffeeDecorator {
public WithMilk(Coffee coffee) {
super(coffee);
}
public double cost() {
return super.cost() + 3;
}
}
public class DecoratorDemo {
public static void main(String[] args) {
Coffee simpleCoffee = new SimpleCoffee();
System.out.println("Cost of simple coffee: " + simpleCoffee.cost());
Coffee milkCoffee = new WithMilk(simpleCoffee);
System.out.println("Cost of coffee with milk: " + milkCoffee.cost());
Coffee sugarMilkCoffee = new WithSugar(milkCoffee);
System.out.println("Cost of coffee with milk and sugar: " + sugarMilkCoffee.cost());
}
}
Coffee 接口定义了对象的核心功能。
WithSugar 和 WithMilk 是装饰器类,动态地增加新的功能。
5. 外观模式 (Facade Pattern)
外观模式为复杂的子系统提供一个统一的接口,使得客户端通过简单的接口访问复杂的子系统,简化系统的使用。
实现方式
定义一个外观类,它包含多个子系统的接口。
客户端通过外观类与子系统交互,隐藏了子系统的复杂性。
Java实现
// 子系统类1
class CPU {
public void process() {
System.out.println("CPU processing");
// 子系统类2
class Memory {
public void load() {
System.out.println("Memory loading");
}
}
// 子系统类3
class HardDrive {
public void read() {
System.out.println("HardDrive reading data");
}
}
// 外观类
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 start() {
System.out.println("Starting the computer...");
cpu.process();
memory.load();
hardDrive.read();
System.out.println("Computer started successfully!");
}
}
public class FacadeDemo {
public static void main(String[] args) {
ComputerFacade computer = new ComputerFacade();
computer.start(); // 输出: Starting the computer... CPU processing Memory loading HardDrive reading data Computer started successfully!
}
}ComputerFacade 类作为外观类,隐藏了子系统 CPU、Memory 和 HardDrive 的复杂性。客户端只需要与外观类交互,简化了系统的使用。
6. 享元模式 (Flyweight Pattern)
享元模式通过共享对象来有效地支持大量的细粒度对象,尤其适用于创建大量对象的场景,能够节省内存并提高性能。
实现方式
定义一个享元工厂,用来管理对象的共享。
将共享的部分提取到外部,通过享元对象的共享来减少内存使用。
Java实现
// 享元接口
interface Flyweight {
void operation(int extrinsicState);
}
// 具体享元类
class ConcreteFlyweight implements Flyweight {
private String intrinsicState;
public ConcreteFlyweight(String state) {
this.intrinsicState = state;
}
public void operation(int extrinsicState) {
System.out.println("Intrinsic State: " + intrinsicState + ", Extrinsic State: " + extrinsicState);
}
}
// 享元工厂类
class FlyweightFactory {
private Map<String, Flyweight> flyweights = new HashMap<>();
public Flyweight getFlyweight(String state) {
Flyweight flyweight = flyweights.get(state);
if (flyweight == null) {
flyweight = new ConcreteFlyweight(state);
flyweights.put(state, flyweight);
}
return flyweight;
}
}
public class FlyweightDemo {
public static void main(String[] args) {
FlyweightFactory factory = new FlyweightFactory();
Flyweight flyweight1 = factory.getFlyweight("State1");
flyweight1.operation(1);
Flyweight flyweight2 = factory.getFlyweight("State1");
flyweight2.operation(2);
Flyweight flyweight3 = factory.getFlyweight("State2");
flyweight3.operation(3);
System.out.println(flyweight1 == flyweight2); // 输出: true, 因为它们共享相同的状态
}
}
ConcreteFlyweight 类实现了享元接口,存储了不可变的内部状态(intrinsic state)。
FlyweightFactory 管理着享元对象的创建与共享。
7. 代理模式 (Proxy Pattern)
代理模式为其他对象提供代理,以控制对该对象的访问。它可以用于延迟初始化、访问控制、缓存、日志记录等功能。
实现方式
定义一个代理接口,它与真实对象接口相同。
代理类在客户端请求时,控制对真实对象的访问,可能还会做一些额外的操作。
Java实现
// 真实主题类
class RealSubject {
public void request() {
System.out.println("RealSubject: Handling request.");
}
}
// 代理类
class Proxy {
private RealSubject realSubject;
public void request() {
if (realSubject == null) {
realSubject = new RealSubject();
}
realSubject.request(); // 代理处理请求
}
}
public class ProxyDemo {
public static void main(String[] args) {
Proxy proxy = new Proxy();
proxy.request(); // 输出: RealSubject: Handling request.
}
}
Proxy 类控制对 RealSubject 的访问。客户端通过代理对象来访问实际的操作,这样可以在代理中添加额外的功能,如延迟加载、访问控制等。