裝飾模式(包裝模式)—結構型

結構型簡介

結構型模式主要總結了一些類或對象組合在一起的經典結構,這些經典的結構可以解決特定應用場景的問題。結構型模式包括:代理模式、橋接模式、裝飾器模式、適配器模式、門面模式、組合模式、享元模式。

簡介

裝飾模式(Decorator Pattern)主要解決繼承過於複雜的問題,通過組合來替代繼承;也就是說是繼承關係的一種替代方案之一;

UML圖

UML圖中各個部分代表的含義如下:

組件類

public abstract class Component {
    public abstract void operate();
}

組件具體實現類

public class ConcreteComponent extends Component {
    @Override
    public void operate() {
        
    }
}

抽象裝飾類(如果裝飾邏輯單一,只有一個的情況下我們可以省略該抽象類,直接是具體的裝飾者)

public abstract class Decorator extends Component {
    private Component mComponent;

    public Decorator(Component mComponent) {
        this.mComponent = mComponent;
    }

    @Override
    public void operate() {
        mComponent.operate();
    }
}

抽象裝飾類具體實現類

public class ConcreteDecoratorA extends Decorator {
    public ConcreteDecoratorA(Component mComponent) {
        super(mComponent);
    }

    @Override
    public void operate() {
        operateA();
        super.operate();
        operateB();
    }

    public void operateA() {
        
    }
    public void operateB() {
        
    }
}

裝飾模式在生活中無處不在,比如說牙膏包裝盒,人各種穿着,不管怎麼包裝但是,人還是那個人本質沒有變;

學過Java語言的熟悉IO流,BufferedInputStream,BufferedOutputStream,BufferedReader,BufferedWriter,DataInputStream,DataOutputStream;都是裝飾者,都是對裝飾設計模式的運用;感興趣的可以自行查看源碼;

JDK源碼中的運用

下面以BufferedReader爲例粘貼部分源碼:

Writer:相當於UML圖中的組件類

public abstract class Writer implements Appendable, Closeable, Flushable {
   
    protected Object lock;

    protected Writer() {
        lock = this;
    }
    
    protected Writer(Object lock) {
        if (lock == null) {
            throw new NullPointerException("lock == null");
        }
        this.lock = lock;
    }
    
    public abstract void close() throws IOException;

    public abstract void flush() throws IOException;
    
    public void write(char[] buf) throws IOException {
        write(buf, 0, buf.length);
    }

    public abstract void write(char[] buf, int offset, int count) throws IOException;

    public void write(int oneChar) throws IOException {
        synchronized (lock) {
            char[] oneCharArray = new char[1];
            oneCharArray[0] = (char) oneChar;
            write(oneCharArray);
        }
    }

    public void write(String str) throws IOException {
        write(str, 0, str.length());
    }
    
    public void write(String str, int offset, int count) throws IOException {
        if ((offset | count) < 0 || offset > str.length() - count) {
            throw new StringIndexOutOfBoundsException(str, offset, count);
        }
        char[] buf = new char[count];
        str.getChars(offset, offset + count, buf, 0);
        synchronized (lock) {
            write(buf, 0, buf.length);
        }
    }

    public Writer append(char c) throws IOException {
        write(c);
        return this;
    }
    
    public Writer append(CharSequence csq) throws IOException {
        if (csq == null) {
            csq = "null";
        }
        write(csq.toString());
        return this;
    }

    public Writer append(CharSequence csq, int start, int end) throws IOException {
        if (csq == null) {
            csq = "null";
        }
        write(csq.subSequence(start, end).toString());
        return this;
    }

    boolean checkError() {
        return false;
    }
}

FileWriter(OutputStreamWriter或者其他具體實現類):相當於組件具體實現類(OutputStreamWriter 繼承Writer)

public class FileWriter extends OutputStreamWriter {

    
    public FileWriter(File file) throws IOException {
        super(new FileOutputStream(file));
    }

    public FileWriter(File file, boolean append) throws IOException {
        super(new FileOutputStream(file, append));
    }

    
    public FileWriter(FileDescriptor fd) {
        super(new FileOutputStream(fd));
    }

   
    public FileWriter(String filename) throws IOException {
        super(new FileOutputStream(new File(filename)));
    }

    
    public FileWriter(String filename, boolean append) throws IOException {
        super(new FileOutputStream(filename, append));
    }
}

BufferedWriter:相當於UML圖中的具體裝飾類(BufferedWriter內部持有了Writer的引用)

public class BufferedWriter extends Writer {

    private Writer out;

    private char[] buf;

    private int pos;

    public BufferedWriter(Writer out) {
        this(out, 8192);
    }

    public BufferedWriter(Writer out, int size) {
        super(out);
        if (size <= 0) {
            throw new IllegalArgumentException("size <= 0");
        }
        this.out = out;
        this.buf = new char[size];
    }

    @Override
    public void close() throws IOException {
        synchronized (lock) {
            if (isClosed()) {
                return;
            }

            Throwable thrown = null;
            try {
                flushInternal();
            } catch (Throwable e) {
                thrown = e;
            }
            buf = null;

            try {
                out.close();
            } catch (Throwable e) {
                if (thrown == null) {
                    thrown = e;
                }
            }
            out = null;

            if (thrown != null) {
                SneakyThrow.sneakyThrow(thrown);
            }
        }
    }

    @Override
    public void flush() throws IOException {
        synchronized (lock) {
            checkNotClosed();
            flushInternal();
            out.flush();
        }
    }

    private void checkNotClosed() throws IOException {
        if (isClosed()) {
            throw new IOException("BufferedWriter is closed");
        }
    }

    private void flushInternal() throws IOException {
        if (pos > 0) {
            out.write(buf, 0, pos);
        }
        pos = 0;
    }

    private boolean isClosed() {
        return out == null;
    }

    public void newLine() throws IOException {
        write(System.lineSeparator());
    }

    @Override
    public void write(char[] buffer, int offset, int count) throws IOException {
        synchronized (lock) {
            checkNotClosed();
            if (buffer == null) {
                throw new NullPointerException("buffer == null");
            }
            Arrays.checkOffsetAndCount(buffer.length, offset, count);
            if (pos == 0 && count >= this.buf.length) {
                out.write(buffer, offset, count);
                return;
            }
            int available = this.buf.length - pos;
            if (count < available) {
                available = count;
            }
            if (available > 0) {
                System.arraycopy(buffer, offset, this.buf, pos, available);
                pos += available;
            }
            if (pos == this.buf.length) {
                out.write(this.buf, 0, this.buf.length);
                pos = 0;
                if (count > available) {
                    offset += available;
                    available = count - available;
                    if (available >= this.buf.length) {
                        out.write(buffer, offset, available);
                        return;
                    }

                    System.arraycopy(buffer, offset, this.buf, pos, available);
                    pos += available;
                }
            }
        }
    }

   
    @Override
    public void write(int oneChar) throws IOException {
        synchronized (lock) {
            checkNotClosed();
            if (pos >= buf.length) {
                out.write(buf, 0, buf.length);
                pos = 0;
            }
            buf[pos++] = (char) oneChar;
        }
    }

    @Override
    public void write(String str, int offset, int count) throws IOException {
        synchronized (lock) {
            checkNotClosed();
            if (count <= 0) {
                return;
            }
            if (offset < 0 || offset > str.length() - count) {
                throw new StringIndexOutOfBoundsException(str, offset, count);
            }
            if (pos == 0 && count >= buf.length) {
                char[] chars = new char[count];
                str.getChars(offset, offset + count, chars, 0);
                out.write(chars, 0, count);
                return;
            }
            int available = buf.length - pos;
            if (count < available) {
                available = count;
            }
            if (available > 0) {
                str.getChars(offset, offset + available, buf, pos);
                pos += available;
            }
            if (pos == buf.length) {
                out.write(this.buf, 0, this.buf.length);
                pos = 0;
                if (count > available) {
                    offset += available;
                    available = count - available;
                    if (available >= buf.length) {
                        char[] chars = new char[count];
                        str.getChars(offset, offset + available, chars, 0);
                        out.write(chars, 0, available);
                        return;
                    }
                    str.getChars(offset, offset + available, buf, pos);
                    pos += available;
                }
            }
        }
    }
}

在Android源碼也有對裝飾模式的運用

Context類做Android的都不陌生,毫不誇張的說幾乎每天都在用,四大組件每個裏面都有他的直接或間接的引用到;Context本質上是一個抽象類,在裝飾設計模式相當於抽象組件,在其內部定義了大量的抽象方法,比如我經常用到的startService和startActivity方法。通過查看Context源碼是不是感覺很多方法很熟悉;

package android.content;

//省略很多方法和其他包名等
public abstract class Context {
  
    public abstract AssetManager getAssets();

    public abstract Resources getResources();

    public abstract Looper getMainLooper();

    @NonNull
    public final CharSequence getText(@StringRes int resId) {
        return getResources().getText(resId);
    }

    @NonNull
    public final String getString(@StringRes int resId) {
        return getResources().getString(resId);
    }

    @NonNull
    public final String getString(@StringRes int resId, Object... formatArgs) {
        return getResources().getString(resId, formatArgs);
    }


    @ColorInt
    public final int getColor(@ColorRes int id) {
        return getResources().getColor(id, getTheme());
    }

    @Nullable
    public final Drawable getDrawable(@DrawableRes int id) {
        return getResources().getDrawable(id, getTheme());
    }

    @NonNull
    public final ColorStateList getColorStateList(@ColorRes int id) {
        return getResources().getColorStateList(id, getTheme());
    }

    public abstract void setTheme(@StyleRes int resid);
 
    @ViewDebug.ExportedProperty(deepExport = true)
    public abstract Resources.Theme getTheme();

    public abstract ClassLoader getClassLoader();

    public abstract String getPackageName();
    
    @UnsupportedAppUsage
    public abstract String getBasePackageName();

    @NonNull
    public String getOpPackageName() {
        throw new RuntimeException("Not implemented. Must override in a subclass.");
    }

    /** Return the full application info for this context's package. */
    public abstract ApplicationInfo getApplicationInfo();

    public abstract String getPackageResourcePath();

    public abstract String getPackageCodePath();

    @Deprecated
    @UnsupportedAppUsage
    public File getSharedPrefsFile(String name) {
        return getSharedPreferencesPath(name);
    }

    public abstract SharedPreferences getSharedPreferences(String name, @PreferencesMode int mode);

    public abstract SharedPreferences getSharedPreferences(File file, @PreferencesMode int mode);

    public abstract boolean moveSharedPreferencesFrom(Context sourceContext, String name);

    public abstract boolean deleteSharedPreferences(String name);

    /** @hide */
    public abstract void reloadSharedPreferences();

    public abstract FileInputStream openFileInput(String name)
        throws FileNotFoundException;

    public abstract FileOutputStream openFileOutput(String name, @FileMode int mode)
        throws FileNotFoundException;

    public abstract boolean deleteFile(String name);


    public abstract File getFileStreamPath(String name);

    
    public abstract File getSharedPreferencesPath(String name);

    public abstract File getDataDir();

    public abstract File getFilesDir();

    public abstract File getNoBackupFilesDir();
   
    @Nullable
    public abstract File getExternalFilesDir(@Nullable String type);

    public abstract File getObbDir();

    public abstract File[] getObbDirs();

    public abstract File getCacheDir();

    public abstract File getCodeCacheDir();

    @Nullable
    public abstract File getExternalCacheDir();
    
    @Nullable
    @SystemApi
    public abstract File getPreloadsFileCache();

    public abstract File[] getExternalCacheDirs();

    public abstract File[] getExternalMediaDirs();

    public abstract String[] fileList();

    public abstract File getDir(String name, @FileMode int mode);
   
    public abstract SQLiteDatabase openOrCreateDatabase(String name,
            @DatabaseMode int mode, CursorFactory factory);

    public abstract SQLiteDatabase openOrCreateDatabase(String name,
            @DatabaseMode int mode, CursorFactory factory,
            @Nullable DatabaseErrorHandler errorHandler);

    public abstract void startActivity(@RequiresPermission Intent intent);

    public abstract void startActivity(@RequiresPermission Intent intent,
            @Nullable Bundle options);

    @UnsupportedAppUsage
    public void startActivityForResult(
            @NonNull String who, Intent intent, int requestCode, @Nullable Bundle options) {
        throw new RuntimeException("This method is only implemented for Activity-based Contexts. "
                + "Check canStartActivityForResult() before calling.");
    }

    public abstract void startActivities(@RequiresPermission Intent[] intents);

    public abstract void startActivities(@RequiresPermission Intent[] intents, Bundle options);

    public abstract void sendBroadcast(@RequiresPermission Intent intent);

    public abstract void sendBroadcast(@RequiresPermission Intent intent,
            @Nullable String receiverPermission);

    @SystemApi
    public abstract void sendBroadcast(Intent intent,
            @Nullable String receiverPermission,
            @Nullable Bundle options);

    @UnsupportedAppUsage
    public abstract void sendBroadcast(Intent intent,
            String receiverPermission, int appOp);

    public abstract void sendOrderedBroadcast(@RequiresPermission Intent intent,
            @Nullable String receiverPermission);

    public abstract void sendOrderedBroadcast(@RequiresPermission @NonNull Intent intent,
            @Nullable String receiverPermission, @Nullable BroadcastReceiver resultReceiver,
            @Nullable Handler scheduler, int initialCode, @Nullable String initialData,
            @Nullable Bundle initialExtras);

    @SystemApi
    public abstract void sendOrderedBroadcast(@NonNull Intent intent,
            @Nullable String receiverPermission, @Nullable Bundle options,
            @Nullable BroadcastReceiver resultReceiver, @Nullable Handler scheduler,
            int initialCode, @Nullable String initialData, @Nullable Bundle initialExtras);

    @Nullable
    public abstract Intent registerReceiver(@Nullable BroadcastReceiver receiver,
                                            IntentFilter filter);
    
    @Nullable
    public abstract Intent registerReceiver(@Nullable BroadcastReceiver receiver,
                                            IntentFilter filter,
                                            @RegisterReceiverFlags int flags);
    @Nullable
    public abstract Intent registerReceiver(BroadcastReceiver receiver,
            IntentFilter filter, @Nullable String broadcastPermission,
            @Nullable Handler scheduler);

    @Nullable
    public abstract Intent registerReceiver(BroadcastReceiver receiver,
            IntentFilter filter, @Nullable String broadcastPermission,
            @Nullable Handler scheduler, @RegisterReceiverFlags int flags);

    @Nullable
    @RequiresPermission(android.Manifest.permission.INTERACT_ACROSS_USERS_FULL)
    @UnsupportedAppUsage
    public abstract Intent registerReceiverAsUser(BroadcastReceiver receiver,
            UserHandle user, IntentFilter filter, @Nullable String broadcastPermission,
            @Nullable Handler scheduler);

    public abstract void unregisterReceiver(BroadcastReceiver receiver);

    @Nullable
    public abstract ComponentName startService(Intent service);
    @Nullable
    public abstract ComponentName startForegroundService(Intent service);
 
    public abstract boolean stopService(Intent service);

    @Nullable
    @RequiresPermission(android.Manifest.permission.INTERACT_ACROSS_USERS)
    @UnsupportedAppUsage
    public abstract ComponentName startServiceAsUser(Intent service, UserHandle user);

    public abstract boolean bindService(@RequiresPermission Intent service,
            @NonNull ServiceConnection conn, @BindServiceFlags int flags);


    public boolean bindService(@RequiresPermission @NonNull Intent service,
            @BindServiceFlags int flags, @NonNull @CallbackExecutor Executor executor,
            @NonNull ServiceConnection conn) {
        throw new RuntimeException("Not implemented. Must override in a subclass.");
    }

    @RequiresPermission(android.Manifest.permission.INTERACT_ACROSS_USERS)
    @UnsupportedAppUsage
    public boolean bindServiceAsUser(Intent service, ServiceConnection conn, int flags,
            Handler handler, UserHandle user) {
        throw new RuntimeException("Not implemented. Must override in a subclass.");
    }
   
    public abstract void unbindService(@NonNull ServiceConnection conn);

    /**
     * Return the handle to a system-level service by name. The class of the
     * returned object varies by the requested name. Currently available names
     * are:
     *
     * <dl>
     *  <dt> {@link #WINDOW_SERVICE} ("window")
     *  <dd> The top-level window manager in which you can place custom
     *  windows.  The returned object is a {@link android.view.WindowManager}.
     *  <dt> {@link #LAYOUT_INFLATER_SERVICE} ("layout_inflater")
     *  <dd> A {@link android.view.LayoutInflater} for inflating layout resources
     *  in this context.
     *  <dt> {@link #ACTIVITY_SERVICE} ("activity")
     *  <dd> A {@link android.app.ActivityManager} for interacting with the
     *  global activity state of the system.
     *  <dt> {@link #POWER_SERVICE} ("power")
     *  <dd> A {@link android.os.PowerManager} for controlling power
     *  management.
     *  <dt> {@link #ALARM_SERVICE} ("alarm")
     *  <dd> A {@link android.app.AlarmManager} for receiving intents at the
     *  time of your choosing.
     *  <dt> {@link #NOTIFICATION_SERVICE} ("notification")
     *  <dd> A {@link android.app.NotificationManager} for informing the user
     *   of background events.
     *  <dt> {@link #KEYGUARD_SERVICE} ("keyguard")
     *  <dd> A {@link android.app.KeyguardManager} for controlling keyguard.
     *  <dt> {@link #LOCATION_SERVICE} ("location")
     *  <dd> A {@link android.location.LocationManager} for controlling location
     *   (e.g., GPS) updates.
     *  <dt> {@link #SEARCH_SERVICE} ("search")
     *  <dd> A {@link android.app.SearchManager} for handling search.
     *  <dt> {@link #VIBRATOR_SERVICE} ("vibrator")
     *  <dd> A {@link android.os.Vibrator} for interacting with the vibrator
     *  hardware.
     *  <dt> {@link #CONNECTIVITY_SERVICE} ("connection")
     *  <dd> A {@link android.net.ConnectivityManager ConnectivityManager} for
     *  handling management of network connections.
     *  <dt> {@link #IPSEC_SERVICE} ("ipsec")
     *  <dd> A {@link android.net.IpSecManager IpSecManager} for managing IPSec on
     *  sockets and networks.
     *  <dt> {@link #WIFI_SERVICE} ("wifi")
     *  <dd> A {@link android.net.wifi.WifiManager WifiManager} for management of Wi-Fi
     *  connectivity.  On releases before NYC, it should only be obtained from an application
     *  context, and not from any other derived context to avoid memory leaks within the calling
     *  process.
     *  <dt> {@link #WIFI_AWARE_SERVICE} ("wifiaware")
     *  <dd> A {@link android.net.wifi.aware.WifiAwareManager WifiAwareManager} for management of
     * Wi-Fi Aware discovery and connectivity.
     *  <dt> {@link #WIFI_P2P_SERVICE} ("wifip2p")
     *  <dd> A {@link android.net.wifi.p2p.WifiP2pManager WifiP2pManager} for management of
     * Wi-Fi Direct connectivity.
     * <dt> {@link #INPUT_METHOD_SERVICE} ("input_method")
     * <dd> An {@link android.view.inputmethod.InputMethodManager InputMethodManager}
     * for management of input methods.
     * <dt> {@link #UI_MODE_SERVICE} ("uimode")
     * <dd> An {@link android.app.UiModeManager} for controlling UI modes.
     * <dt> {@link #DOWNLOAD_SERVICE} ("download")
     * <dd> A {@link android.app.DownloadManager} for requesting HTTP downloads
     * <dt> {@link #BATTERY_SERVICE} ("batterymanager")
     * <dd> A {@link android.os.BatteryManager} for managing battery state
     * <dt> {@link #JOB_SCHEDULER_SERVICE} ("taskmanager")
     * <dd>  A {@link android.app.job.JobScheduler} for managing scheduled tasks
     * <dt> {@link #NETWORK_STATS_SERVICE} ("netstats")
     * <dd> A {@link android.app.usage.NetworkStatsManager NetworkStatsManager} for querying network
     * usage statistics.
     * <dt> {@link #HARDWARE_PROPERTIES_SERVICE} ("hardware_properties")
     * <dd> A {@link android.os.HardwarePropertiesManager} for accessing hardware properties.
     * </dl>
     *
     * <p>Note:  System services obtained via this API may be closely associated with
     * the Context in which they are obtained from.  In general, do not share the
     * service objects between various different contexts (Activities, Applications,
     * Services, Providers, etc.)
     *
     * <p>Note: Instant apps, for which {@link PackageManager#isInstantApp()} returns true,
     * don't have access to the following system services: {@link #DEVICE_POLICY_SERVICE},
     * {@link #FINGERPRINT_SERVICE}, {@link #KEYGUARD_SERVICE}, {@link #SHORTCUT_SERVICE},
     * {@link #USB_SERVICE}, {@link #WALLPAPER_SERVICE}, {@link #WIFI_P2P_SERVICE},
     * {@link #WIFI_SERVICE}, {@link #WIFI_AWARE_SERVICE}. For these services this method will
     * return <code>null</code>.  Generally, if you are running as an instant app you should always
     * check whether the result of this method is {@code null}.
     *
     * <p>Note: When implementing this method, keep in mind that new services can be added on newer
     * Android releases, so if you're looking for just the explicit names mentioned above, make sure
     * to return {@code null} when you don't recognize the name &mdash; if you throw a
     * {@link RuntimeException} exception instead, you're app might break on new Android releases.
     *
     * @param name The name of the desired service.
     *
     * @return The service or {@code null} if the name does not exist.
     *
     * @see #WINDOW_SERVICE
     * @see android.view.WindowManager
     * @see #LAYOUT_INFLATER_SERVICE
     * @see android.view.LayoutInflater
     * @see #ACTIVITY_SERVICE
     * @see android.app.ActivityManager
     * @see #POWER_SERVICE
     * @see android.os.PowerManager
     * @see #ALARM_SERVICE
     * @see android.app.AlarmManager
     * @see #NOTIFICATION_SERVICE
     * @see android.app.NotificationManager
     * @see #KEYGUARD_SERVICE
     * @see android.app.KeyguardManager
     * @see #LOCATION_SERVICE
     * @see android.location.LocationManager
     * @see #SEARCH_SERVICE
     * @see android.app.SearchManager
     * @see #SENSOR_SERVICE
     * @see android.hardware.SensorManager
     * @see #STORAGE_SERVICE
     * @see android.os.storage.StorageManager
     * @see #VIBRATOR_SERVICE
     * @see android.os.Vibrator
     * @see #CONNECTIVITY_SERVICE
     * @see android.net.ConnectivityManager
     * @see #WIFI_SERVICE
     * @see android.net.wifi.WifiManager
     * @see #AUDIO_SERVICE
     * @see android.media.AudioManager
     * @see #MEDIA_ROUTER_SERVICE
     * @see android.media.MediaRouter
     * @see #TELEPHONY_SERVICE
     * @see android.telephony.TelephonyManager
     * @see #TELEPHONY_SUBSCRIPTION_SERVICE
     * @see android.telephony.SubscriptionManager
     * @see #CARRIER_CONFIG_SERVICE
     * @see android.telephony.CarrierConfigManager
     * @see #INPUT_METHOD_SERVICE
     * @see android.view.inputmethod.InputMethodManager
     * @see #UI_MODE_SERVICE
     * @see android.app.UiModeManager
     * @see #DOWNLOAD_SERVICE
     * @see android.app.DownloadManager
     * @see #BATTERY_SERVICE
     * @see android.os.BatteryManager
     * @see #JOB_SCHEDULER_SERVICE
     * @see android.app.job.JobScheduler
     * @see #NETWORK_STATS_SERVICE
     * @see android.app.usage.NetworkStatsManager
     * @see android.os.HardwarePropertiesManager
     * @see #HARDWARE_PROPERTIES_SERVICE
     */
    public abstract @Nullable Object getSystemService(@ServiceName @NonNull String name);

    @SuppressWarnings("unchecked")
    public final @Nullable <T> T getSystemService(@NonNull Class<T> serviceClass) {
        String serviceName = getSystemServiceName(serviceClass);
        return serviceName != null ? (T)getSystemService(serviceName) : null;
    }

    @CheckResult(suggest="#enforceUriPermission(Uri,int,int,String)")
    @PackageManager.PermissionResult
    public abstract int checkUriPermission(Uri uri, int pid, int uid,
            @Intent.AccessUriMode int modeFlags);

    @PackageManager.PermissionResult
    public abstract int checkUriPermission(Uri uri, int pid, int uid,
            @Intent.AccessUriMode int modeFlags, IBinder callerToken);

    public abstract Context createPackageContext(String packageName,
            @CreatePackageOptions int flags) throws PackageManager.NameNotFoundException;

    @UnsupportedAppUsage
    public abstract Context createApplicationContext(ApplicationInfo application,
            @CreatePackageOptions int flags) throws PackageManager.NameNotFoundException;
   
    public abstract Context createContextForSplit(String splitName)
            throws PackageManager.NameNotFoundException;
    @TestApi
    public UserHandle getUser() {
        return android.os.Process.myUserHandle();
    }

    @TestApi
    public @UserIdInt int getUserId() {
        return android.os.UserHandle.myUserId();
    }

    public abstract Context createConfigurationContext(
            @NonNull Configuration overrideConfiguration);

    public abstract Context createDisplayContext(@NonNull Display display);

    @SystemApi
    public abstract Context createCredentialProtectedStorageContext();

    public abstract DisplayAdjustments getDisplayAdjustments(int displayId);

    @TestApi
    public abstract Display getDisplay();

    @TestApi
    public abstract int getDisplayId();

    public abstract void updateDisplay(int displayId);

    public boolean isRestricted() {
        return false;
    }

    public IApplicationThread getIApplicationThread() {
        throw new RuntimeException("Not implemented. Must override in a subclass.");
    }

    public Handler getMainThreadHandler() {
        throw new RuntimeException("Not implemented. Must override in a subclass.");
    }

}

其實現類是android.app.ContextImpl,ContextImpl繼承Context,並實現了Context中的抽象方法;這裏的ContextImpl相當於組件的具體實現類;

class ContextImpl extends Context {

    @Override
    public ComponentName startService(Intent service) {
        warnIfCallingFromSystemProcess();
        return startServiceCommon(service, false, mUser);
    }

    @Override
    public ComponentName startForegroundService(Intent service) {
        warnIfCallingFromSystemProcess();
        return startServiceCommon(service, true, mUser);
    }

    @Override
    public boolean stopService(Intent service) {
        warnIfCallingFromSystemProcess();
        return stopServiceCommon(service, mUser);
    }

 @Override
    public boolean bindService(Intent service, ServiceConnection conn, int flags) {
        warnIfCallingFromSystemProcess();
        return bindServiceCommon(service, conn, flags, null, mMainThread.getHandler(), null,
                getUser());
    }

    @Override
    public boolean bindService(
            Intent service, int flags, Executor executor, ServiceConnection conn) {
        warnIfCallingFromSystemProcess();
        return bindServiceCommon(service, conn, flags, null, null, executor, getUser());
    }

     @Override
    public void sendBroadcast(Intent intent) {
        warnIfCallingFromSystemProcess();
        String resolvedType = intent.resolveTypeIfNeeded(getContentResolver());
        try {
            intent.prepareToLeaveProcess(this);
            ActivityManager.getService().broadcastIntent(
                    mMainThread.getApplicationThread(), intent, resolvedType, null,
                    Activity.RESULT_OK, null, null, null, AppOpsManager.OP_NONE, null, false, false,
                    getUserId());
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
        }
    }

@Override
    public void sendBroadcast(Intent intent, String receiverPermission) {
        warnIfCallingFromSystemProcess();
        String resolvedType = intent.resolveTypeIfNeeded(getContentResolver());
        String[] receiverPermissions = receiverPermission == null ? null
                : new String[] {receiverPermission};
        try {
            intent.prepareToLeaveProcess(this);
            ActivityManager.getService().broadcastIntent(
                    mMainThread.getApplicationThread(), intent, resolvedType, null,
                    Activity.RESULT_OK, null, null, receiverPermissions, AppOpsManager.OP_NONE,
                    null, false, false, getUserId());
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
        }
    }

 @Override
    public void sendOrderedBroadcast(Intent intent, String receiverPermission) {
        warnIfCallingFromSystemProcess();
        String resolvedType = intent.resolveTypeIfNeeded(getContentResolver());
        String[] receiverPermissions = receiverPermission == null ? null
                : new String[] {receiverPermission};
        try {
            intent.prepareToLeaveProcess(this);
            ActivityManager.getService().broadcastIntent(
                    mMainThread.getApplicationThread(), intent, resolvedType, null,
                    Activity.RESULT_OK, null, null, receiverPermissions, AppOpsManager.OP_NONE,
                    null, true, false, getUserId());
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
        }
    }


}

Android中的Activity相比大家都很熟,從繼承上說其實也是一個Content,但是Activity不是直接繼承Content的,而是繼承ContextThemeWrapper;

public class Activity extends ContextThemeWrapper {

    @MainThread
    @CallSuper
    protected void onCreate(@Nullable Bundle savedInstanceState) {

    }
}

而ContextThemeWrapper又繼承ContextWrapper 

public class ContextThemeWrapper extends ContextWrapper {
    @UnsupportedAppUsage
    private int mThemeResource;
    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 123768723)
    private Resources.Theme mTheme;
    @UnsupportedAppUsage
    private LayoutInflater mInflater;
    private Configuration mOverrideConfiguration;
    @UnsupportedAppUsage
    private Resources mResources;

}

最終ContextWrapper才繼承Context,是不是感覺很複雜,其實這裏就是一個典型的裝飾模式的運用,ContextWrapper就是我們要找的裝飾着,在ContextWrapper中有一個Context的引用。

public class ContextWrapper extends Context {
    @UnsupportedAppUsage
    Context mBase;

    public ContextWrapper(Context base) {
        mBase = base;
    }
    
}

我們再看一下ContextWrapper內部的來自於組件的方法;

public class ContextWrapper extends Context {

     @Override
    public ComponentName startService(Intent service) {
        return mBase.startService(service);
    }

    @Override
    public boolean stopService(Intent name) {
        return mBase.stopService(name);
    }

}

從上面的源碼可以看出ContextWrapper中的startService方法也僅僅是調用了組件實現類(ContextImpl)中對應的方法而已,對於具體方法的包裝擴展則有ContextWrapper的具體子類完成;比如我們的Service,Activity,Application.

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章