橋接模式(Bridge Pattern)定義和使用場景
- 定義
橋接模式(Bridge Pattern):將抽象部分與它的實現部分分離,使它們都可以獨立地變化。它是一種對象結構型模式,又稱為柄體(Handle and Body)模式或接口(Interface)模式。
實現系統可能有多個角度分類,每一種角度都可能變化,那么把這種多角度分類給分離出來讓他們獨立變化,減少他們之間耦合。
- 使用場景
如果一個系統需要在構件的抽象化和具體角色之間增加更多的靈活性,避免在兩個層次之間建立靜態的繼承聯系,可以通過橋接模式使它們在抽象層建立一個關聯關系。對于那些不希望使用繼承或因為多層次繼承導致系統類的個數急劇增加的系統,橋接模式尤為適用。一個類存在兩個獨立變化的維度,且這兩個維度都需要進行擴展。 -
橋接模式的UML類圖
橋接模式
Abstraction:抽象部分。該類保持一個對實現部分的引用,抽象部分中的方法需要調用實現部分的對象來實現,該類一般為抽象類。
RefinedAbstraction:優化的抽象部分。抽象部分的具體實現,該類一般是對抽象部分的方法進行完善和擴展。
Implementor:實現部分。可以為接口或者抽象類,其方法不一定要與抽象部分中的一致,一般情況下是由實現部分提供基本的操作,而抽象部分定義的則是基于實現部分這些基本操作的業務方法。
ConcreteImplementorA/ConcreteImplementorB:實現部分的具體實現。完善實現部分中方法定義的具體邏輯。
Client:客戶類,客戶端程序。 - 生活實例闡述
- 開關與具體的電器,開關的類型有很多,也是有各種各樣的,這兩者是獨立的且又有耦合。
- 電腦的主機箱和電腦廠商,主機箱的樣式是有多種多樣的而電腦的廠商也是有很多,所以這也可以是一種橋接模式。
3.Java語言通過Java虛擬機實現了平臺的無關性,Java語言的程序和運行Java成語的平臺的,這也是橋接模式的一種實現。
橋接模式的簡單代碼實例
用不同顏色的筆畫出不同形狀的圖形,畫筆的顏色可以是有多種多樣的,畫的圖形也可以是有正方形、長方形等不同的圖形。
public interface Paint {
void userPaintColor();
}
public class RedPaint implements Paint{
@Override
public void userPaintColor() {
System.out.println("用紅色的筆去畫");
}
}
public class BluePaint implements Paint{
@Override
public void userPaintColor() {
System.out.println("用藍色的筆去畫");
}
}
public abstract class DrawShape {
protected Paint paintImple;
public DrawShape(Paint paintImple){
this.paintImple=paintImple;
}
public abstract void drawShape();
}
public class CircleShape extends DrawShape{
public CircleShape(Paint paintImple) {
super(paintImple);
}
@Override
public void drawShape() {
paintImple.userPaintColor();
System.out.println("畫出圓形");
}
}
public class SquareShape extends DrawShape{
public SquareShape(Paint paintImple) {
super(paintImple);
}
@Override
public void drawShape() {
paintImple.userPaintColor();
System.out.println("畫出正方形");
}
}
public class TestDemo {
public static void main(String a[])
{
CircleShape circleShape=new CircleShape(new RedPaint());
circleShape.drawShape();
SquareShape squareShape=new SquareShape(new RedPaint());
squareShape.drawShape();
}
}
打印結果
Android源碼中的橋接模式實現
在View的視圖層中,CheckBox、CompoundButton、Button、TextView和View之間構成一個繼承關系的視圖層級,每一層級都僅僅是對一個類型控件的描述,定義了該類控件所擁有的基本屬性和行為,但是將它們真正繪制到屏幕的部分是由與View相關的功能實現類DisplayList、HardwareLayer和Canvas負責。
-
另外一個比較典型Window與WindowManager之間的關系,Window和PhoneWindow構成窗口的抽象部分,其中Window類為該抽象部分的抽象接口,PhoneWindow為抽象部分具體的實現及擴展。WindowsManager則為實現部分的基類,WindowManagerImpl為實現部分具體的實現及擴展,其使用WindowManagerGlobal通過IWindowManager接口與WindowManagerService進行交互,并由WMS完成具體的窗口管理工具。
image1.png
WindowManagerServer
在Android的framework層主要就是由WindowManagerServer與另外一個系統服務ActivityManagerService還有View所構成。
WindowManagerService在SystemServer中的main方法中啟動
public static void main(String[] args) {
new SystemServer().run();
}
public SystemServer() {
// Check for factory test mode.
mFactoryTestMode = FactoryTest.getMode();
}
private void run() {
try {
Trace.traceBegin(Trace.TRACE_TAG_SYSTEM_SERVER, "InitBeforeStartServices");
// If a device's clock is before 1970 (before 0), a lot of
// APIs crash dealing with negative numbers, notably
// java.io.File#setLastModified, so instead we fake it and
// hope that time from cell towers or NTP fixes it shortly.
if (System.currentTimeMillis() < EARLIEST_SUPPORTED_TIME) {
Slog.w(TAG, "System clock is before 1970; setting to 1970.");
SystemClock.setCurrentTimeMillis(EARLIEST_SUPPORTED_TIME);
}
// If the system has "persist.sys.language" and friends set, replace them with
// "persist.sys.locale". Note that the default locale at this point is calculated
// using the "-Duser.locale" command line flag. That flag is usually populated by
// AndroidRuntime using the same set of system properties, but only the system_server
// and system apps are allowed to set them.
//
// NOTE: Most changes made here will need an equivalent change to
// core/jni/AndroidRuntime.cpp
if (!SystemProperties.get("persist.sys.language").isEmpty()) {
final String languageTag = Locale.getDefault().toLanguageTag();
SystemProperties.set("persist.sys.locale", languageTag);
SystemProperties.set("persist.sys.language", "");
SystemProperties.set("persist.sys.country", "");
SystemProperties.set("persist.sys.localevar", "");
}
// Here we go!
Slog.i(TAG, "Entered the Android system server!");
EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_SYSTEM_RUN, SystemClock.uptimeMillis());
// In case the runtime switched since last boot (such as when
// the old runtime was removed in an OTA), set the system
// property so that it is in sync. We can't do this in
// libnativehelper's JniInvocation::Init code where we already
// had to fallback to a different runtime because it is
// running as root and we need to be the system user to set
// the property. http://b/11463182
SystemProperties.set("persist.sys.dalvik.vm.lib.2", VMRuntime.getRuntime().vmLibrary());
// Enable the sampling profiler.
if (SamplingProfilerIntegration.isEnabled()) {
SamplingProfilerIntegration.start();
mProfilerSnapshotTimer = new Timer();
mProfilerSnapshotTimer.schedule(new TimerTask() {
@Override
public void run() {
SamplingProfilerIntegration.writeSnapshot("system_server", null);
}
}, SNAPSHOT_INTERVAL, SNAPSHOT_INTERVAL);
}
// Mmmmmm... more memory!
VMRuntime.getRuntime().clearGrowthLimit();
// The system server has to run all of the time, so it needs to be
// as efficient as possible with its memory usage.
VMRuntime.getRuntime().setTargetHeapUtilization(0.8f);
// Some devices rely on runtime fingerprint generation, so make sure
// we've defined it before booting further.
Build.ensureFingerprintProperty();
// Within the system server, it is an error to access Environment paths without
// explicitly specifying a user.
Environment.setUserRequired(true);
// Within the system server, any incoming Bundles should be defused
// to avoid throwing BadParcelableException.
BaseBundle.setShouldDefuse(true);
// Ensure binder calls into the system always run at foreground priority.
BinderInternal.disableBackgroundScheduling(true);
// Increase the number of binder threads in system_server
BinderInternal.setMaxThreads(sMaxBinderThreads);
// Prepare the main looper thread (this thread).
android.os.Process.setThreadPriority(
android.os.Process.THREAD_PRIORITY_FOREGROUND);
android.os.Process.setCanSelfBackground(false);
Looper.prepareMainLooper();
// Initialize native services.
System.loadLibrary("android_servers");
// Check whether we failed to shut down last time we tried.
// This call may not return.
performPendingShutdown();
// Initialize the system context.
createSystemContext();
// Create the system service manager.
mSystemServiceManager = new SystemServiceManager(mSystemContext);
LocalServices.addService(SystemServiceManager.class, mSystemServiceManager);
} finally {
Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
}
// Start services.
try {
Trace.traceBegin(Trace.TRACE_TAG_SYSTEM_SERVER, "StartServices");
// 安裝應用需要的
startBootstrapServices();
startCoreServices();
// 啟動服務
startOtherServices();
} catch (Throwable ex) {
Slog.e("System", "******************************************");
Slog.e("System", "************ Failure starting system services", ex);
throw ex;
} finally {
Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
}
// For debug builds, log event loop stalls to dropbox for analysis.
if (StrictMode.conditionallyEnableDebugLogging()) {
Slog.i(TAG, "Enabled StrictMode for system server main thread.");
}
// Loop forever.
Looper.loop();
throw new RuntimeException("Main thread loop unexpectedly exited");
}
private void startOtherServices() {
final Context context = mSystemContext;
VibratorService vibrator = null;
IMountService mountService = null;
NetworkManagementService networkManagement = null;
NetworkStatsService networkStats = null;
NetworkPolicyManagerService networkPolicy = null;
ConnectivityService connectivity = null;
NetworkScoreService networkScore = null;
NsdService serviceDiscovery= null;
WindowManagerService wm = null;
SerialService serial = null;
NetworkTimeUpdateService networkTimeUpdater = null;
CommonTimeManagementService commonTimeMgmtService = null;
InputManagerService inputManager = null;
TelephonyRegistry telephonyRegistry = null;
ConsumerIrService consumerIr = null;
MmsServiceBroker mmsService = null;
HardwarePropertiesManagerService hardwarePropertiesService = null;
boolean disableStorage = SystemProperties.getBoolean("config.disable_storage", false);
boolean disableBluetooth = SystemProperties.getBoolean("config.disable_bluetooth", false);
boolean disableLocation = SystemProperties.getBoolean("config.disable_location", false);
boolean disableSystemUI = SystemProperties.getBoolean("config.disable_systemui", false);
boolean disableNonCoreServices = SystemProperties.getBoolean("config.disable_noncore", false);
boolean disableNetwork = SystemProperties.getBoolean("config.disable_network", false);
boolean disableNetworkTime = SystemProperties.getBoolean("config.disable_networktime", false);
boolean disableRtt = SystemProperties.getBoolean("config.disable_rtt", false);
boolean disableMediaProjection = SystemProperties.getBoolean("config.disable_mediaproj",
false);
boolean disableSerial = SystemProperties.getBoolean("config.disable_serial", false);
boolean disableSearchManager = SystemProperties.getBoolean("config.disable_searchmanager",
false);
boolean disableTrustManager = SystemProperties.getBoolean("config.disable_trustmanager",
false);
boolean disableTextServices = SystemProperties.getBoolean("config.disable_textservices", false);
boolean disableSamplingProfiler = SystemProperties.getBoolean("config.disable_samplingprof",
false);
boolean isEmulator = SystemProperties.get("ro.kernel.qemu").equals("1");
try {
Slog.i(TAG, "Reading configuration...");
SystemConfig.getInstance();
traceBeginAndSlog("StartSchedulingPolicyService");
ServiceManager.addService("scheduling_policy", new SchedulingPolicyService());
Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
mSystemServiceManager.startService(TelecomLoaderService.class);
traceBeginAndSlog("StartTelephonyRegistry");
telephonyRegistry = new TelephonyRegistry(context);
ServiceManager.addService("telephony.registry", telephonyRegistry);
Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
traceBeginAndSlog("StartEntropyMixer");
mEntropyMixer = new EntropyMixer(context);
Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
mContentResolver = context.getContentResolver();
Slog.i(TAG, "Camera Service");
mSystemServiceManager.startService(CameraService.class);
// The AccountManager must come before the ContentService
traceBeginAndSlog("StartAccountManagerService");
mSystemServiceManager.startService(ACCOUNT_SERVICE_CLASS);
Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
traceBeginAndSlog("StartContentService");
mSystemServiceManager.startService(CONTENT_SERVICE_CLASS);
Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
traceBeginAndSlog("InstallSystemProviders");
mActivityManagerService.installSystemProviders();
Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
traceBeginAndSlog("StartVibratorService");
vibrator = new VibratorService(context);
ServiceManager.addService("vibrator", vibrator);
Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
traceBeginAndSlog("StartConsumerIrService");
consumerIr = new ConsumerIrService(context);
ServiceManager.addService(Context.CONSUMER_IR_SERVICE, consumerIr);
Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
traceBeginAndSlog("StartAlarmManagerService");
mSystemServiceManager.startService(AlarmManagerService.class);
Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
traceBeginAndSlog("InitWatchdog");
final Watchdog watchdog = Watchdog.getInstance();
watchdog.init(context, mActivityManagerService);
Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
traceBeginAndSlog("StartInputManagerService");
inputManager = new InputManagerService(context);
Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
traceBeginAndSlog("StartWindowManagerService");
wm = WindowManagerService.main(context, inputManager,
mFactoryTestMode != FactoryTest.FACTORY_TEST_LOW_LEVEL,
!mFirstBoot, mOnlyCore);
ServiceManager.addService(Context.WINDOW_SERVICE, wm);
ServiceManager.addService(Context.INPUT_SERVICE, inputManager);
Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
traceBeginAndSlog("StartVrManagerService");
mSystemServiceManager.startService(VrManagerService.class);
Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
mActivityManagerService.setWindowManager(wm);
inputManager.setWindowManagerCallbacks(wm.getInputMonitor());
inputManager.start();
// TODO: Use service dependencies instead.
mDisplayManagerService.windowManagerAndInputReady();
// Skip Bluetooth if we have an emulator kernel
// TODO: Use a more reliable check to see if this product should
// support Bluetooth - see bug 988521
if (isEmulator) {
Slog.i(TAG, "No Bluetooth Service (emulator)");
} else if (mFactoryTestMode == FactoryTest.FACTORY_TEST_LOW_LEVEL) {
Slog.i(TAG, "No Bluetooth Service (factory test)");
} else if (!context.getPackageManager().hasSystemFeature
(PackageManager.FEATURE_BLUETOOTH)) {
Slog.i(TAG, "No Bluetooth Service (Bluetooth Hardware Not Present)");
} else if (disableBluetooth) {
Slog.i(TAG, "Bluetooth Service disabled by config");
} else {
mSystemServiceManager.startService(BluetoothService.class);
}
traceBeginAndSlog("ConnectivityMetricsLoggerService");
mSystemServiceManager.startService(MetricsLoggerService.class);
Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
traceBeginAndSlog("IpConnectivityMetrics");
mSystemServiceManager.startService(IpConnectivityMetrics.class);
Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
traceBeginAndSlog("PinnerService");
mSystemServiceManager.startService(PinnerService.class);
Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
} catch (RuntimeException e) {
Slog.e("System", "******************************************");
Slog.e("System", "************ Failure starting core service", e);
}
.....
省略其他代碼
通過這個方法獲取WindowmanagerService的實例,并且把他加到ServiceMange里面,然后其他進程都可以通過ServiceManager查詢獲取到WindowsManagerService。
wm = WindowManagerService.main(context, inputManager,
mFactoryTestMode != FactoryTest.FACTORY_TEST_LOW_LEVEL,
!mFirstBoot, mOnlyCore);
ServiceManager.addService(Context.WINDOW_SERVICE, wm);
WindowsManagerService的mian方法
private WindowManagerService(Context context, InputManagerService inputManager,
boolean haveInputMethods, boolean showBootMsgs, boolean onlyCore) {
mContext = context;
mHaveInputMethods = haveInputMethods;
mAllowBootMessages = showBootMsgs;
mOnlyCore = onlyCore;
mLimitedAlphaCompositing = context.getResources().getBoolean(
com.android.internal.R.bool.config_sf_limitedAlpha);
mHasPermanentDpad = context.getResources().getBoolean(
com.android.internal.R.bool.config_hasPermanentDpad);
mInTouchMode = context.getResources().getBoolean(
com.android.internal.R.bool.config_defaultInTouchMode);
mDrawLockTimeoutMillis = context.getResources().getInteger(
com.android.internal.R.integer.config_drawLockTimeoutMillis);
mAllowAnimationsInLowPowerMode = context.getResources().getBoolean(
com.android.internal.R.bool.config_allowAnimationsInLowPowerMode);
mInputManager = inputManager; // Must be before createDisplayContentLocked.
mDisplayManagerInternal = LocalServices.getService(DisplayManagerInternal.class);
mDisplaySettings = new DisplaySettings();
mDisplaySettings.readSettingsLocked();
mWallpaperControllerLocked = new WallpaperController(this);
mWindowPlacerLocked = new WindowSurfacePlacer(this);
mLayersController = new WindowLayersController(this);
LocalServices.addService(WindowManagerPolicy.class, mPolicy);
mPointerEventDispatcher = new PointerEventDispatcher(mInputManager.monitorInput(TAG_WM));
mFxSession = new SurfaceSession();
mDisplayManager = (DisplayManager)context.getSystemService(Context.DISPLAY_SERVICE);
mDisplays = mDisplayManager.getDisplays();
for (Display display : mDisplays) {
createDisplayContentLocked(display);
}
mKeyguardDisableHandler = new KeyguardDisableHandler(mContext, mPolicy);
mPowerManager = (PowerManager)context.getSystemService(Context.POWER_SERVICE);
mPowerManagerInternal = LocalServices.getService(PowerManagerInternal.class);
mPowerManagerInternal.registerLowPowerModeObserver(
new PowerManagerInternal.LowPowerModeListener() {
@Override
public void onLowPowerModeChanged(boolean enabled) {
synchronized (mWindowMap) {
if (mAnimationsDisabled != enabled && !mAllowAnimationsInLowPowerMode) {
mAnimationsDisabled = enabled;
dispatchNewAnimatorScaleLocked(null);
}
}
}
});
mAnimationsDisabled = mPowerManagerInternal.getLowPowerModeEnabled();
mScreenFrozenLock = mPowerManager.newWakeLock(
PowerManager.PARTIAL_WAKE_LOCK, "SCREEN_FROZEN");
mScreenFrozenLock.setReferenceCounted(false);
mAppTransition = new AppTransition(context, this);
mAppTransition.registerListenerLocked(mActivityManagerAppTransitionNotifier);
mBoundsAnimationController =
new BoundsAnimationController(mAppTransition, UiThread.getHandler());
mActivityManager = ActivityManagerNative.getDefault();
mAmInternal = LocalServices.getService(ActivityManagerInternal.class);
mAppOps = (AppOpsManager)context.getSystemService(Context.APP_OPS_SERVICE);
AppOpsManager.OnOpChangedInternalListener opListener =
new AppOpsManager.OnOpChangedInternalListener() {
@Override public void onOpChanged(int op, String packageName) {
updateAppOpsState();
}
};
mAppOps.startWatchingMode(AppOpsManager.OP_SYSTEM_ALERT_WINDOW, null, opListener);
mAppOps.startWatchingMode(AppOpsManager.OP_TOAST_WINDOW, null, opListener);
// Get persisted window scale setting
mWindowAnimationScaleSetting = Settings.Global.getFloat(context.getContentResolver(),
Settings.Global.WINDOW_ANIMATION_SCALE, mWindowAnimationScaleSetting);
mTransitionAnimationScaleSetting = Settings.Global.getFloat(context.getContentResolver(),
Settings.Global.TRANSITION_ANIMATION_SCALE, mTransitionAnimationScaleSetting);
setAnimatorDurationScale(Settings.Global.getFloat(context.getContentResolver(),
Settings.Global.ANIMATOR_DURATION_SCALE, mAnimatorDurationScaleSetting));
// Track changes to DevicePolicyManager state so we can enable/disable keyguard.
IntentFilter filter = new IntentFilter();
filter.addAction(DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED);
mContext.registerReceiver(mBroadcastReceiver, filter);
mSettingsObserver = new SettingsObserver();
mHoldingScreenWakeLock = mPowerManager.newWakeLock(
PowerManager.SCREEN_BRIGHT_WAKE_LOCK | PowerManager.ON_AFTER_RELEASE, TAG_WM);
mHoldingScreenWakeLock.setReferenceCounted(false);
mAnimator = new WindowAnimator(this);
mAllowTheaterModeWakeFromLayout = context.getResources().getBoolean(
com.android.internal.R.bool.config_allowTheaterModeWakeFromWindowLayout);
LocalServices.addService(WindowManagerInternal.class, new LocalService());
initPolicy();
// Add ourself to the Watchdog monitors.
Watchdog.getInstance().addMonitor(this);
SurfaceControl.openTransaction();
try {
createWatermarkInTransaction();
} finally {
SurfaceControl.closeTransaction();
}
showEmulatorDisplayOverlayIfNeeded();
}
public static WindowManagerService main(final Context context,
final InputManagerService im,
final boolean haveInputMethods, final boolean showBootMsgs,
final boolean onlyCore) {
final WindowManagerService[] holder = new WindowManagerService[1];
DisplayThread.getHandler().runWithScissors(new Runnable() {
@Override
public void run() {
holder[0] = new WindowManagerService(context, im,
haveInputMethods, showBootMsgs, onlyCore);
}
}, 0);
return holder[0];
}
橋接模式的優點
- 橋接模式實現了抽象化與實現化的脫耦。他們兩個互相獨立,不會影響到對方。
- 對于兩個獨立變化的維度,使用橋接模式再適合不過了。
- 對于“具體的抽象類”所做的改變,是不會影響到客戶。