概念

桥接模式是一种结构型设计模式,它通过将抽象与其实现分离来解耦。它使用接口(抽象类)作为桥梁,将一个抽象类与其实现类的代码分别独立开来,从而使它们可以各自独立地变化。桥接模式的核心思想是“组合优于继承”。

示例

为了更好地理解桥接模式,我们来看一个简单的示例:假设有一个形状类,其中有一个颜色属性。此时,如果我们使用继承来实现不同颜色的形状类,就需要创建许多子类,使代码结构变得复杂且难以维护。而使用桥接模式,则可以将形状和颜色分别抽象出来,从而将它们独立开来。

下面是一个简单的代码示例:

public interface Color {
    String getColor();
}

public class Red implements Color {
    @Override
    public String getColor() {
        return "红色";
    }
}

public class Blue implements Color {
    @Override
    public String getColor() {
        return "蓝色";
    }
}

public abstract class Shape {
    protected Color color;

    public Shape(Color color) {
        this.color = color;
    }

    public abstract void draw();
}

public class Rectangle extends Shape {
    public Rectangle(Color color) {
        super(color);
    }

    @Override
    public void draw() {
        System.out.println("绘制一个" + color.getColor() + "的矩形");
    }
}

public class Circle extends Shape {
    public Circle(Color color) {
        super(color);
    }

    @Override
    public void draw() {
        System.out.println("绘制一个" + color.getColor() + "的圆形");
    }
}

在上面的代码中,我们首先定义了一个颜色接口,并分别实现了红色和蓝色。然后,我们定义了一个抽象的形状类,其中有一个颜色属性和一个抽象方法draw()。最后,我们实现了具体的矩形和圆形类,并在构造函数中传入了一个颜色对象。

这样,我们就将形状和颜色分别抽象出来,从而实现了解耦。当我们需要创建不同颜色的形状时,只需要创建不同颜色的对象并传入即可。

Android应用

在Android应用开发中,桥接模式通常用于将业务逻辑和UI分离。例如,在MVP(Model-View-Presenter)模式中,Presenter通常充当桥接的角色,将View和Model分离开来。Presenter通过接口(抽象类)与View进行交互,并通过Model来获取数据。

下面是一个简单的MVP示例:

public interface LoginView {
    void showProgress();
    void hideProgress();
    void setUsernameError();
    void setPasswordError();
    void navigateToHome();
}

public interface LoginPresenter {
    void validateCredentials(String username, String password);
}

public class LoginPresenterImpl implements LoginPresenter {
    private LoginView loginView;
    private LoginModel loginModel;

    public LoginPresenterImpl(LoginView loginView) {
        this.loginView = loginView;
        loginModel = new LoginModelImpl();
    }

    @Override
    public void validateCredentials(String username, String password) {
        if (TextUtils.isEmpty(username)) {
            loginView.setUsernameError();
            return;
        }

        if (TextUtils.isEmpty(password)) {
            loginView.setPasswordError();
            return;
        }

        loginView.showProgress();

        loginModel.login(username, password, new LoginModel.OnLoginFinishedListener() {
            @Override
            public void onUsernameError() {
                loginView.hideProgress();
                loginView.setUsernameError();
            }

            @Override
            public void onPasswordError() {
                loginView.hideProgress();
                loginView.setPasswordError();
            }

            @Override
            public void onSuccess() {
                loginView.hideProgress();
                loginView.navigateToHome();
            }
        });
    }
}

public interface LoginModel {
    interface OnLoginFinishedListener {
        void onUsernameError();
        void onPasswordError();
        void onSuccess();
    }

    void login(String username, String password, OnLoginFinishedListener listener);
}

public class LoginModelImpl implements LoginModel {
    @Override
    public void login(final String username, final String password, final OnLoginFinishedListener listener) {
        new Handler().postDelayed(new Runnable() {
            @Override
            public void run() {
                if (username.equals("user") && password.equals("password")) {
                    listener.onSuccess();
                } else if (!TextUtils.isEmpty(username)) {
                    listener.onPasswordError();
                } else {
                    listener.onUsernameError();
                }
            }
        }, 2000);
    }
}

在上面的代码中,我们定义了一个LoginView接口,其中包含了一些用于显示UI的方法。然后,我们定义了一个LoginPresenter接口,它与LoginView接口相连,并通过LoginModel来获取数据。最后,我们实现了具体的LoginPresenterImpl和LoginModelImpl类。

通过这种方式,我们将UI和业务逻辑分开,从而使代码结构更清晰,易于维护。

源码解析

在Android源码中,桥接模式也有广泛的应用。例如,在View系统中,View和ViewGroup之间就采用了桥接模式来实现解耦。

在View系统中,View是Android系统中的基本UI组件,而ViewGroup则是一种容器组件,用于将多个View组合在一起。在这两个组件中,都有一个名为LayoutParams的内部类,用于描述组件的布局参数。

在早期的Android版本中,View和ViewGroup之间是通过继承来实现布局参数的传递的。但是这样会导致代码结构复杂且难以维护,因此在Android 2.2版本中,Google采用了桥接模式来重构View系统,从而使其更加灵活和易于维护。

下面是一个简单的代码示例,展示了View和ViewGroup之间是如何通过桥接模式来传递布局参数的:

public class View {
    private LayoutParams mLayoutParams;

    public void setLayoutParams(LayoutParams params) {
        mLayoutParams = params;
    }

    public LayoutParams getLayoutParams() {
        return mLayoutParams;
    }

    public static class LayoutParams {
        // 布局参数的属性
    }
}

public class ViewGroup extends View {
    private ArrayList<View> mChildList = new ArrayList<>();

    public void addView(View child) {
        mChildList.add(child);
        child.setParent(this);
    }

    public void removeView(View child) {
        mChildList.remove(child);
        child.setParent(null);
    }

    public void removeAllViews() {
        for (View child : mChildList) {
            child.setParent(null);
        }
        mChildList.clear();
    }

    public static class LayoutParams extends View.LayoutParams {
        // 布局参数的属性
    }
}

在上面的代码中,我们首先定义了一个View类,并在其中包含了一个LayoutParams内部类。然后,我们定义了一个ViewGroup类,它继承自View,并增加了一个mChildList成员变量和相关的方法,用于管理子View。

最后,我们在ViewGroup中定义了一个LayoutParams内部类,并继承自View.LayoutParams。通过这种方式,我们将布局参数从View中分离出来,使得View和ViewGroup之间的关系更加清晰。

总之,桥接模式是一种常用的设计模式,它可以帮助我们将抽象和实现分离开来,从而实现解耦。