設計模式解析—橋接設計模式

橋接模式(Bridge Pattern)定義和使用場景
  • 定義
    橋接模式(Bridge Pattern):將抽象部分與它的實現部分分離,使它們都可以獨立地變化。它是一種對象結構型模式,又稱為柄體(Handle and Body)模式或接口(Interface)模式。

實現系統可能有多個角度分類,每一種角度都可能變化,那么把這種多角度分類給分離出來讓他們獨立變化,減少他們之間耦合。

  • 使用場景
    如果一個系統需要在構件的抽象化和具體角色之間增加更多的靈活性,避免在兩個層次之間建立靜態的繼承聯系,可以通過橋接模式使它們在抽象層建立一個關聯關系。對于那些不希望使用繼承或因為多層次繼承導致系統類的個數急劇增加的系統,橋接模式尤為適用。一個類存在兩個獨立變化的維度,且這兩個維度都需要進行擴展。
  • 橋接模式的UML類圖


    橋接模式

    Abstraction:抽象部分。該類保持一個對實現部分的引用,抽象部分中的方法需要調用實現部分的對象來實現,該類一般為抽象類。
    RefinedAbstraction:優化的抽象部分。抽象部分的具體實現,該類一般是對抽象部分的方法進行完善和擴展。
    Implementor:實現部分。可以為接口或者抽象類,其方法不一定要與抽象部分中的一致,一般情況下是由實現部分提供基本的操作,而抽象部分定義的則是基于實現部分這些基本操作的業務方法。
    ConcreteImplementorA/ConcreteImplementorB:實現部分的具體實現。完善實現部分中方法定義的具體邏輯。
    Client:客戶類,客戶端程序。

  • 生活實例闡述
  1. 開關與具體的電器,開關的類型有很多,也是有各種各樣的,這兩者是獨立的且又有耦合。
  2. 電腦的主機箱和電腦廠商,主機箱的樣式是有多種多樣的而電腦的廠商也是有很多,所以這也可以是一種橋接模式。
    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();
    }
}

打印結果


image.png
Android源碼中的橋接模式實現
  1. 在View的視圖層中,CheckBox、CompoundButton、Button、TextView和View之間構成一個繼承關系的視圖層級,每一層級都僅僅是對一個類型控件的描述,定義了該類控件所擁有的基本屬性和行為,但是將它們真正繪制到屏幕的部分是由與View相關的功能實現類DisplayList、HardwareLayer和Canvas負責。

  2. 另外一個比較典型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];
    }
橋接模式的優點
  1. 橋接模式實現了抽象化與實現化的脫耦。他們兩個互相獨立,不會影響到對方。
  2. 對于兩個獨立變化的維度,使用橋接模式再適合不過了。
  3. 對于“具體的抽象類”所做的改變,是不會影響到客戶。
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,156評論 6 531
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,401評論 3 415
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 176,069評論 0 373
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,873評論 1 309
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,635評論 6 408
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,128評論 1 323
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,203評論 3 441
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,365評論 0 288
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 48,881評論 1 334
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,733評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,935評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,475評論 5 358
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,172評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,582評論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,821評論 1 282
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,595評論 3 390
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,908評論 2 372

推薦閱讀更多精彩內容

  • 1 場景問題# 1.1 發送提示消息## 考慮這樣一個實際的業務功能:發送提示消息。基本上所有帶業務流程處理的系統...
    七寸知架構閱讀 5,040評論 5 63
  • 設計模式匯總 一、基礎知識 1. 設計模式概述 定義:設計模式(Design Pattern)是一套被反復使用、多...
    MinoyJet閱讀 3,957評論 1 15
  • 一、面向對象的六大原則單一職責Single Responsibility Principle,縮寫SRP。定義:對...
    為夢想戰斗閱讀 395評論 0 2
  • 莎士比亞說,時間會割破現實的華麗精致,會將平行線刻上美人的額角,什么都逃不過它橫掃的鐮刀。 “去年今日此門中,人面...
    林夏薩摩閱讀 935評論 1 4
  • 初春的晚霞推開走廊的窗子, 青澀的人兒羞紅了臉頰。 你問,為什么? 是云彩背后的余暉, 迷醉了我的眼睛。 微涼的晚...
    遇見季風閱讀 234評論 2 1