结构型
适配器模式
定义
它允许将一个类的接口转换成客户端期望的另一个接口。适配器模式通常用于使不兼容的接口能够一起工作。
适配器模式的角色
- 目标接口(Target):客户端期望的接口。
- 适配者(Adaptee):需要被适配的类或接口。
- 适配器(Adapter):将适配者的接口转换成目标接口的类。
java
// 目标接口
interface Printer {
void print();
}
// 适配者类
class LegacyPrinter {
void printDocument() {
System.out.println("Legacy Printer is printing a document.");
}
}
// 适配器类
class LegacyPrinterAdapter implements Printer {
private LegacyPrinter legacyPrinter;
public LegacyPrinterAdapter(LegacyPrinter legacyPrinter) {
this.legacyPrinter = legacyPrinter;
}
@Override
public void print() {
legacyPrinter.printDocument();
}
}
// 客户端代码
public class AdapterPatternExample {
public static void main(String[] args) {
// 创建适配者对象
LegacyPrinter legacyPrinter = new LegacyPrinter();
// 创建适配器对象
Printer printer = new LegacyPrinterAdapter(legacyPrinter);
// 使用适配器调用目标接口的方法
printer.print();
}
}
jdk或者android系统上的应用
- jdk
目标接口:List 接口。
适配者:数组(String[])。
适配器:Arrays.asList() 方法返回的 List 实现类。
java
// 创建一个数组
String[] array = {"Apple", "Banana", "Cherry"};
// 使用 Arrays.asList() 将数组适配为 List
List<String> list = Arrays.asList(array);
// 现在可以使用 List 的方法操作数组
System.out.println(list); // 输出: [Apple, Banana, Cherry]
- android
目标接口:RecyclerView.Adapter,定义了如何将数据绑定到 RecyclerView 的视图上。
适配者:数据源(List)。
适配器:MyAdapter 类,将数据源适配到 RecyclerView 中。
java
// 数据类
public class Item {
private String name;
public Item(String name) {
this.name = name;
}
public String getName() {
return name;
}
}
// 适配器类
public class MyAdapter extends RecyclerView.Adapter<MyAdapter.ViewHolder> {
private List<Item> items;
public MyAdapter(List<Item> items) {
this.items = items;
}
@Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_layout, parent, false);
return new ViewHolder(view);
}
@Override
public void onBindViewHolder(ViewHolder holder, int position) {
Item item = items.get(position);
holder.textView.setText(item.getName());
}
@Override
public int getItemCount() {
return items.size();
}
public static class ViewHolder extends RecyclerView.ViewHolder {
public TextView textView;
public ViewHolder(View itemView) {
super(itemView);
textView = itemView.findViewById(R.id.textView);
}
}
}
// 使用适配器
List<Item> items = new ArrayList<>();
items.add(new Item("Apple"));
items.add(new Item("Banana"));
items.add(new Item("Cherry"));
RecyclerView recyclerView = findViewById(R.id.recyclerView);
recyclerView.setLayoutManager(new LinearLayoutManager(this));
MyAdapter adapter = new MyAdapter(items);
recyclerView.setAdapter(adapter);
桥接模式
定义
它将抽象部分与实现部分分离,使它们可以独立变化。这种模式通过提供一个桥接结构,使得抽象和实现可以在不相互影响的情况下进行扩展。
主要角色
- 抽象类(Abstraction):定义抽象接口,并包含一个对实现类对象的引用。
- 扩展抽象类(Refined Abstraction):扩展抽象类,通常是对抽象类的具体实现。
- 实现类接口(Implementor):定义实现类的接口,通常是一个抽象类或接口。
- 具体实现类(Concrete Implementor):实现实现类接口的具体类。
java
// 实现类接口:颜色
interface Color {
void applyColor();
}
java
// 具体实现类:红色
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");
}
}
java
// 抽象类:形状
abstract class Shape {
protected Color color;
public Shape(Color color) {
this.color = color;
}
abstract void draw();
}
java
// 扩展抽象类:圆形
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();
}
}
java
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
}
}
jdk或者android系统上的应用
在 Android 中,View 是抽象的 UI 组件,而 Drawable 是具体的绘制实现。View 通过桥接模式与 Drawable 分离,使得 View 可以独立于具体的绘制逻辑。
- 抽象部分:View 类及其子类(如 Button、TextView)。
- 实现部分:Drawable 类及其子类(如 BitmapDrawable、ShapeDrawable)。
java
// 抽象部分
Button button = new Button(context);
// 实现部分(Drawable 是具体的绘制实现)
Drawable background = new ColorDrawable(Color.RED);
button.setBackground(background);
组合模式(Composite)
定义
将对象组合成树形结构以表示"部分-整体"的层次结构。组合模式使得客户端可以统一对待单个对象和组合对象。
主要角色
- 组件(Component):定义所有对象的通用接口,可以是抽象类或接口。
- 叶子节点(Leaf):表示树形结构中的叶子节点,没有子节点。
- 复合节点(Composite):表示树形结构中的分支节点,包含子节点。
java
// 组件接口:文件系统组件
interface FileSystemComponent {
void showDetails();
}
java
// 叶子节点:文件
class File implements FileSystemComponent {
private String name;
public File(String name) {
this.name = name;
}
@Override
public void showDetails() {
System.out.println("File: " + name);
}
}
java
// 复合节点:文件夹
class Directory implements FileSystemComponent {
private String name;
private List<FileSystemComponent> components = new ArrayList<>();
public Directory(String name) {
this.name = name;
}
public void addComponent(FileSystemComponent component) {
components.add(component);
}
public void removeComponent(FileSystemComponent component) {
components.remove(component);
}
@Override
public void showDetails() {
System.out.println("Directory: " + name);
for (FileSystemComponent component : components) {
component.showDetails();
}
}
}
java
public class CompositePatternDemo {
public static void main(String[] args) {
// 创建文件
FileSystemComponent file1 = new File("file1.txt");
FileSystemComponent file2 = new File("file2.txt");
FileSystemComponent file3 = new File("file3.txt");
// 创建文件夹
Directory dir1 = new Directory("Dir1");
Directory dir2 = new Directory("Dir2");
// 将文件添加到文件夹
dir1.addComponent(file1);
dir1.addComponent(file2);
dir2.addComponent(file3);
// 将文件夹添加到另一个文件夹
Directory rootDir = new Directory("Root");
rootDir.addComponent(dir1);
rootDir.addComponent(dir2);
// 显示文件系统结构
rootDir.showDetails();
}
}
jdk或者android系统上的应用
1、在 Java 集合框架中,Map 和 List 的实现类(如 HashMap、ArrayList)可以嵌套使用,形成树形结构。这种嵌套结构可以看作是组合模式的一种应用。
- 组件(Component):java.util.Map 或 java.util.List。
- 叶子节点(Leaf):具体的键值对或列表项。
- 复合节点(Composite):嵌套的 Map 或 List。
java
// 复合节点
Map<String, Object> root = new HashMap<>();
// 叶子节点
root.put("name", "John Doe");
// 嵌套的复合节点
Map<String, Object> address = new HashMap<>();
address.put("city", "New York");
address.put("zip", "10001");
// 将嵌套的复合节点添加到根节点
root.put("address", address);
System.out.println(root);
2、在 Android 的 UI 框架中,View 和 ViewGroup 是组合模式的典型应用。
- 组件(Component):android.view.View 是所有 UI 组件的基类。
- 叶子节点(Leaf):如 TextView、Button 等,它们没有子视图。
- 复合节点(Composite):如 LinearLayout、RelativeLayout 等,它们可以包含其他视图。
java
// 复合节点
LinearLayout layout = new LinearLayout(context);
layout.setOrientation(LinearLayout.VERTICAL);
// 叶子节点
TextView textView = new TextView(context);
textView.setText("Hello, World!");
Button button = new Button(context);
button.setText("Click Me");
// 将叶子节点添加到复合节点
layout.addView(textView);
layout.addView(button);
// 显示 UI
Activity activity = ...;
activity.setContentView(layout);
装饰模式(Decorator)
定义
通过将对象放入包含行为的特殊封装对象中来为原对象动态添加新的行为。装饰模式的核心思想是通过组合而非继承来扩展对象的功能。
- 组件接口(Component):定义对象的接口,可以是抽象类或接口。
- 具体组件(Concrete Component):实现组件接口的具体类。
- 装饰器(Decorator):持有一个组件对象的引用,并实现组件接口。
- 具体装饰器(Concrete Decorator):扩展装饰器类,添加新的行为。
jdk或者android系统上的应用
- Java I/O 流
Java 的 I/O 流是装饰模式的经典应用。InputStream 和 OutputStream 是组件接口,FileInputStream 和 FileOutputStream 是具体组件,而 BufferedInputStream、DataInputStream 等是装饰器。
java
// 具体组件
InputStream fileInputStream = new FileInputStream("file.txt");
// 装饰器:添加缓冲功能
InputStream bufferedInputStream = new BufferedInputStream(fileInputStream);
// 装饰器:添加数据读取功能
DataInputStream dataInputStream = new DataInputStream(bufferedInputStream);
- Android 系统中的装饰模式
在 Android 中,ContextWrapper 是装饰模式的典型应用。Context 是组件接口,ContextImpl 是具体组件,而 ContextWrapper 是装饰器。
java
// 具体组件
Context context = new ContextImpl();
// 装饰器:ContextWrapper
ContextWrapper contextWrapper = new ContextWrapper(context);
外观模式(Facade)
定义
它提供了一个统一的接口,用来访问子系统中的一群接口。外观模式定义了一个高层接口,使得子系统更容易使用。
主要角色
- 外观类(Facade):提供一个简单的接口,隐藏子系统的复杂性。
- 子系统类(Subsystem Classes):实现子系统的功能,处理外观类指派的任务。
java
// 子系统类:灯光
class Light {
public void on() {
System.out.println("Light is on");
}
public void off() {
System.out.println("Light is off");
}
}
// 子系统类:音响系统
class SoundSystem {
public void on() {
System.out.println("Sound system is on");
}
public void off() {
System.out.println("Sound system is off");
}
public void setVolume(int level) {
System.out.println("Sound system volume set to " + level);
}
}
// 子系统类:投影仪
class Projector {
public void on() {
System.out.println("Projector is on");
}
public void off() {
System.out.println("Projector is off");
}
public void setInput(String input) {
System.out.println("Projector input set to " + input);
}
}
java
// 外观类:家庭影院外观
class HomeTheaterFacade {
private Light light;
private SoundSystem soundSystem;
private Projector projector;
public HomeTheaterFacade(Light light, SoundSystem soundSystem, Projector projector) {
this.light = light;
this.soundSystem = soundSystem;
this.projector = projector;
}
public void watchMovie() {
System.out.println("Get ready to watch a movie...");
light.off();
soundSystem.on();
soundSystem.setVolume(10);
projector.on();
projector.setInput("DVD");
}
public void endMovie() {
System.out.println("Shutting down the movie theater...");
light.on();
soundSystem.off();
projector.off();
}
}
jdk或者android系统上的应用
在 Android 中,Context 是一个外观类,它提供了一个统一的接口来访问系统资源、启动 Activity、访问文件系统等。
java
Context context = getApplicationContext();
context.startActivity(new Intent(context, AnotherActivity.class));
享元模式(Flyweight)
定义
它通过共享对象来减少内存使用和提高性能。享元模式的核心思想是将对象的内部状态(Intrinsic State)和外部状态(Extrinsic State)分离,内部状态可以被共享,而外部状态由客户端传递。
享元接口(Flyweight):定义享元对象的接口,通常是一个接口或抽象类。
主要角色
- 具体享元类(Concrete Flyweight):实现享元接口,包含内部状态。
- 享元工厂(Flyweight Factory):负责创建和管理享元对象,确保共享。
- 客户端(Client):使用享元对象,并维护外部状态。
假设我们正在开发一个文本编辑器,需要处理大量的字符对象。每个字符都有固定的内部状态(如字符值、字体等),而外部状态(如位置、颜色等)可能会频繁变化。我们可以使用享元模式来共享字符对象,从而减少内存占用。
java
// 享元接口:字符
interface Character {
void display(String color);
}
java
// 具体享元类:具体字符
class ConcreteCharacter implements Character {
private char value; // 内部状态(字符值)
public ConcreteCharacter(char value) {
this.value = value;
}
@Override
public void display(String color) {
System.out.println("Character: " + value + ", Color: " + color);
}
}
java
import java.util.HashMap;
import java.util.Map;
// 享元工厂:字符工厂
class CharacterFactory {
private Map<Character, ConcreteCharacter> characters = new HashMap<>();
public Character getCharacter(char value) {
// 如果字符已经存在,直接返回
if (characters.containsKey(value)) {
return characters.get(value);
}
// 否则创建新的字符对象并缓存
ConcreteCharacter character = new ConcreteCharacter(value);
characters.put(value, character);
return character;
}
}
java
public class FlyweightPatternDemo {
public static void main(String[] args) {
// 创建享元工厂
CharacterFactory factory = new CharacterFactory();
// 获取字符对象(内部状态共享)
Character charA = factory.getCharacter('A');
Character charB = factory.getCharacter('B');
Character charA2 = factory.getCharacter('A'); // 重复使用 'A'
// 显示字符(外部状态由客户端传递)
charA.display("Red");
charB.display("Blue");
charA2.display("Green");
// 验证是否共享
System.out.println("charA == charA2: " + (charA == charA2)); // 输出 true
}
}
jdk或者android系统上的应用
- Java 字符串常量池
Java 中的字符串常量池是享元模式的经典应用。相同的字符串字面量会被共享,而不是创建新的对象。
java
String s1 = "Hello";
String s2 = "Hello";
System.out.println(s1 == s2); // 输出 true,因为 s1 和 s2 指向同一个对象
- Android 的 RecyclerView的ViewHolder
在 Android 的 RecyclerView 中,ViewHolder 的复用机制是享元模式的应用。RecyclerView 会复用已经创建的 ViewHolder,而不是为每个列表项创建新的对象。
java
@Override
public void onBindViewHolder(ViewHolder holder, int position) {
// 复用 ViewHolder,更新外部状态(如数据)
holder.bind(data.get(position));
}
代理模式(Proxy)
定义
它为其他对象提供一个代理对象,并由代理对象控制对原对象的访问。代理模式的核心思想是通过引入一个代理对象,在不改变原始类的情况下,增加额外的功能或控制访问。
主要角色
- 抽象主题(Subject):定义真实主题和代理对象的共同接口。
- 真实主题(Real Subject):实现抽象主题接口,是代理对象所代表的真实对象。
- 代理(Proxy):实现抽象主题接口,并持有对真实主题的引用,可以在调用真实主题之前或之后执行额外的操作。
假设我们有一个图片加载器,加载大图片时可能会消耗大量时间和内存。我们可以使用代理模式来实现延迟加载(Lazy Loading),即只有在真正需要时才加载图片。
java
// 抽象主题:图片接口
interface Image {
void display();
}
java
// 真实主题:真实图片
class RealImage implements Image {
private String filename;
public RealImage(String filename) {
this.filename = filename;
loadFromDisk(); // 模拟加载图片
}
private void loadFromDisk() {
System.out.println("Loading image: " + filename);
}
@Override
public void display() {
System.out.println("Displaying image: " + filename);
}
}
java
// 代理:代理图片
class ProxyImage implements Image {
private String filename;
private RealImage realImage; // 持有对真实主题的引用
public ProxyImage(String filename) {
this.filename = filename;
}
@Override
public void display() {
// 延迟加载:只有在真正需要时才创建真实对象
if (realImage == null) {
realImage = new RealImage(filename);
}
realImage.display();
}
}
java
public class ProxyPatternDemo {
public static void main(String[] args) {
// 创建代理对象
Image image = new ProxyImage("large_image.jpg");
// 第一次访问:加载图片
image.display();
System.out.println("------------");
// 第二次访问:直接显示图片(无需重新加载)
image.display();
}
}
jdk或者android系统上的应用
- 动态代理(java.lang.reflect.Proxy)
Java 提供了动态代理机制,可以在运行时动态创建代理对象。动态代理通常用于实现 AOP(面向切面编程)。
java
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
// 抽象主题
interface Service {
void doSomething();
}
// 真实主题
class RealService implements Service {
@Override
public void doSomething() {
System.out.println("RealService is doing something.");
}
}
// 动态代理
class DynamicProxy implements InvocationHandler {
private Object target;
public DynamicProxy(Object target) {
this.target = target;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("Before method: " + method.getName());
Object result = method.invoke(target, args);
System.out.println("After method: " + method.getName());
return result;
}
}
public class DynamicProxyDemo {
public static void main(String[] args) {
// 创建真实主题
Service realService = new RealService();
// 创建动态代理
Service proxyService = (Service) Proxy.newProxyInstance(
realService.getClass().getClassLoader(),
realService.getClass().getInterfaces(),
new DynamicProxy(realService)
);
// 调用代理对象
proxyService.doSomething();
}
}
- android Binder
在 Android 中,Binder 是跨进程通信(IPC)的核心机制。Binder 使用代理模式来实现客户端和服务端的通信。