结构型模式
什么是结构型模式
结构型模式描述如何将类或对象结合在一起,形成更大的结构,例如搭积木一样一个一个形成一个更大的结构。
结构型模式有分为两种模式:
类结构型模式:类结构型模式关心类和类之间的组合,通过继承来组合类,形成更大的结构。类结构型模式就像子承父业,儿子继承父亲的能力,在此基础上扩展自己的能力。
对象结构型模式:对象结构型模式关心对象和类之间的组合,在一个类中,应用另一个类的对象,形成更大的结构。对象型结构模式就像团队组合,借助他人的力量来完成任务。
组合模式
什么是组合模式?
组合模式是一种结构型模式,它将对象组合成树形结构,并使得客户端可以同一的对待叶子结点和组合节点。
组合模式的核心思想是将对象构建成树形结构,叶子节点是树形结构的基本元素,没有子节点,组合节点是树形结构中的容器,可以有子节点。
组合模式的角色:
- Component(组件):定义的叶子节点和组合节点的公共接口
- Leaf(叶子节点):树形结构的基本元素,实现了Component的接口,没有实现关于管理叶子节点的接口
- Composite(组合节点):树形结构的容器,实现了Component的接口,实现关于管理叶子结点的接口
优点:
- 简化了客户端的代码:客户端可以统一对待叶子节点和组合节点
- 灵活性更强:组合模式可以轻松构建负责的树形结构,可以动态的删除或添加节点
- 符合开闭原则:
缺点:
- 设计复杂:如果树形结构复杂,可能导致类的数量增加
- 性能问题:如果在深度较大的树形结构中,递归影响效率
代码示例
import java.util.ArrayList;
import java.util.List;
// Component:定义文件和文件夹的共同接口
abstract class FileSystemComponent {
protected String name;
public FileSystemComponent(String name) {
this.name = name;
}
public abstract void display(); // 显示文件或文件夹信息
public void add(FileSystemComponent component) {
throw new UnsupportedOperationException("This operation is not supported.");
}
public void remove(FileSystemComponent component) {
throw new UnsupportedOperationException("This operation is not supported.");
}
}
// Leaf:文件类
class File extends FileSystemComponent {
public File(String name) {
super(name);
}
@Override
public void display() {
System.out.println("File: " + name);
}
}
// Composite:文件夹类
class Folder extends FileSystemComponent {
private List<FileSystemComponent> components = new ArrayList<>();
public Folder(String name) {
super(name);
}
@Override
public void display() {
System.out.println("Folder: " + name);
for (FileSystemComponent component : components) {
component.display(); // 递归显示子组件
}
}
@Override
public void add(FileSystemComponent component) {
components.add(component);
}
@Override
public void remove(FileSystemComponent component) {
components.remove(component);
}
}
// 客户端代码
public class CompositePatternDemo {
public static void main(String[] args) {
// 创建文件和文件夹
FileSystemComponent file1 = new File("file1.txt");
FileSystemComponent file2 = new File("file2.txt");
FileSystemComponent folder1 = new Folder("Folder1");
FileSystemComponent folder2 = new Folder("Folder2");
// 构建树形结构
folder1.add(file1);
folder1.add(file2);
folder1.add(folder2);
folder2.add(new File("file3.txt"));
// 显示文件系统结构
folder1.display();
}
}
UML类图
适配器模式
什么是适配器模式?
适配器模式是一种结构型模式,解决由于接口不兼容,无法协同工作的问题。
适配器模式的核心是:
- 复用现有的类
- 实现接口的转换,是不能兼容的接口能够协同工作
适配器模式的两种实现方式:
类适配器模式:
- 使用继承来实现适配器
- 适配器类实现目标接口,继承被适配类,通过重写接口的方法实现适配
对象适配模式:
- 使用组合来实现适配器
- 适配器实现目标接口,持有一个配适配类对象,通过调用对象方法实现接口装换
优点
复用性:可以复用现有的类,而不需要修改它们的代码。
灵活性:对象适配器模式更灵活,可以适配多个被适配类。
解耦:将客户端与被适配类解耦,客户端只需要依赖目标接口。
缺点
复杂性:如果系统中存在大量适配器,可能会增加系统的复杂性。
性能问题:在某些情况下,适配器模式可能会引入额外的性能开销。
示例
假设我们有一个欧洲的电源插头(EuropeanPlug),它只能在欧洲标准的插座上使用。现在我们需要在美国的标准插座上使用这个插头,可以设计一个适配器(EuropeanToUSAdapter),将欧洲插头适配到美国插座。
目标接口(Target)
// 美国插座接口
interface USPlug {
void plugInUS(); // 美国插座的接口方法
}
被适配类(Adaptee)
// 欧洲插头类
class EuropeanPlug {
void plugInEurope() {
System.out.println("Plugged in Europe (220V)");
}
}
适配器类(Adapter)
类适配器模式
// 类适配器:通过继承实现
class EuropeanToUSAdapter extends EuropeanPlug implements USPlug {
@Override
public void plugInUS() {
System.out.println("Adapter converts European plug to US plug");
plugInEurope(); // 调用被适配类的方法
}
}
对象适配器模式
// 对象适配器:通过组合实现
class EuropeanToUSAdapter implements USPlug {
private EuropeanPlug europeanPlug; // 持有被适配类的实例
public EuropeanToUSAdapter(EuropeanPlug europeanPlug) {
this.europeanPlug = europeanPlug;
}
@Override
public void plugInUS() {
System.out.println("Adapter converts European plug to US plug");
europeanPlug.plugInEurope(); // 调用被适配类的方法
}
}
客户端代码
public class AdapterPatternDemo {
public static void main(String[] args) {
// 使用类适配器
USPlug adapter1 = new EuropeanToUSAdapter();
adapter1.plugInUS();
// 使用对象适配器
EuropeanPlug europeanPlug = new EuropeanPlug();
USPlug adapter2 = new EuropeanToUSAdapter(europeanPlug);
adapter2.plugInUS();
}
}
UML类图
类适配器模式
对象适配器
外观模式
什么是外观模式
外观模式是一种结构型设计模式,为复杂的子系统提供了简单的接口,客户端通过调用接口即可操作复杂的子系统。
外观模式的角色:
- 外观类:提供简单的接口,客户端通过这些接口,和负责的子系统做交互
- 子系统类:实现系统的具体功能,外观类会调用子系统类的方法
外观模式的特点:
- 提供调用子系统的接口,简化客户端代码,让客户端和子系统解除耦合
外观模式的优点:
- 简化客户端代码,直接调用外观类接口
- 解耦客户端和子系统
- 易扩展,易维护
- 符合开闭原则
代码示例
假设我们有一个复杂的多媒体系统,包含音频播放器、视频播放器和灯光控制器。我们可以为这个系统创建一个外观类 MultimediaFacade,客户端只需要与 MultimediaFacade 交互,而不需要直接操作各个子系统。
// 子系统类:音频播放器
class AudioPlayer {
public void on() {
System.out.println("Audio Player is on");
}
public void play(String audio) {
System.out.println("Playing audio: " + audio);
}
public void off() {
System.out.println("Audio Player is off");
}
}
// 子系统类:视频播放器
class VideoPlayer {
public void on() {
System.out.println("Video Player is on");
}
public void play(String video) {
System.out.println("Playing video: " + video);
}
public void off() {
System.out.println("Video Player is off");
}
}
// 子系统类:灯光控制器
class LightController {
public void dim() {
System.out.println("Lights are dimmed");
}
public void brighten() {
System.out.println("Lights are brightened");
}
}
// 外观类:多媒体系统
class MultimediaFacade {
private AudioPlayer audioPlayer;
private VideoPlayer videoPlayer;
private LightController lightController;
public MultimediaFacade() {
this.audioPlayer = new AudioPlayer();
this.videoPlayer = new VideoPlayer();
this.lightController = new LightController();
}
public void startMovie(String audio, String video) {
System.out.println("Starting the movie...");
lightController.dim();
audioPlayer.on();
audioPlayer.play(audio);
videoPlayer.on();
videoPlayer.play(video);
}
public void endMovie() {
System.out.println("Ending the movie...");
audioPlayer.off();
videoPlayer.off();
lightController.brighten();
}
}
// 客户端代码
public class FacadePatternDemo {
public static void main(String[] args) {
MultimediaFacade multimediaFacade = new MultimediaFacade();
// 开始播放电影
multimediaFacade.startMovie("Background Music", "Movie Title");
// 结束播放电影
multimediaFacade.endMovie();
}
}
uml
桥接模式
什么是桥接模式
桥接模式是一种结构型设计模式,它的特点是将抽象和实现分类,让两者能够独立,并在抽象中引用(桥接)实现,调用实现的方法完成逻辑实现。
桥接模式的核心思想:
- 实现部分:定义底层的操作逻辑,也就是我要怎么实现
- 抽象部分:定义高层的控制逻辑,也就是我要实现什么
- 桥接:通过在抽象的部分应用实现的对象,建立连接而不会是继承,使得两者可以独立扩展
实现部分只需要对自己的任务进行实现,不需要知道抽象部分的存在;抽象部分定义控制逻辑,我要实现什么样的东西,需要依赖于实现部分,但是不需要知道他的具体实现,只需要去依赖一个具体实现不需要关心它怎么实现。
什么是桥接:
- 桥接就是将抽象和实现关联起来,也就是在抽象的部分应用实现,这个引用的操作就是桥接
- 通过引用而不是继承,使得实现和抽象之间可以相互独立,独立扩展
优点:
- 将抽象和实现进行分离,两者可以独立扩展
- 避免了类爆炸,分离抽象和实现,避免了每一种组合都创建一个类
- 易维护,可扩展
- 符合开闭原则
代码示例
// 实现部分的接口:颜色
interface Color {
void applyColor();
}
// 具体实现类:红色
class RedColor implements Color {
@Override
public void applyColor() {
System.out.println("Applying red color");
}
}
// 具体实现类:绿色
class GreenColor implements Color {
@Override
public void applyColor() {
System.out.println("Applying green 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(); // 使用桥接的颜色
}
}
// 具体抽象类:矩形
class Rectangle extends Shape {
public Rectangle(Color color) {
super(color);
}
@Override
void draw() {
System.out.print("Drawing Rectangle. ");
color.applyColor(); // 使用桥接的颜色
}
}
// 客户端代码
public class BridgePatternDemo {
public static void main(String[] args) {
// 创建颜色对象
Color red = new RedColor();
Color green = new GreenColor();
// 创建形状对象,并桥接颜色
Shape redCircle = new Circle(red);
Shape greenRectangle = new Rectangle(green);
// 绘制形状
redCircle.draw(); // 输出:Drawing Circle. Applying red color
greenRectangle.draw(); // 输出:Drawing Rectangle. Applying green color
}
}
uml