IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 移动开发 -> 面试都会问的Android开发之设计模式,聊聊设计模式6大原则 -> 正文阅读

[移动开发]面试都会问的Android开发之设计模式,聊聊设计模式6大原则

单一职责

对于一个类来说,应该只有一个原因引起它的变化,也就是他所承担的职责应该单一化,不应该承担不同的责任。一个类承担的职责越多说明耦合性越高,越不容易被复用。比如我们常用的用户管理类,里面包含了登录,登出等行为。而在登录登出行为中,一个要将用户信息写入到缓存,一个要从缓存中清楚用户信息。

那么根据单一职责,显然这里写入以及读取缓存具体的方法实现是不该属于此类的,UserManager类只关心登录登出即可,缓存要交给另外的类实现。代码类似如下:

public class UserManager {
    /**
     * 登录
     */
    void login(){
        HttpUtil.login(new Callback(){
            @Override
            void onSuccess(User user){
                //登录完成将user写入缓存
                UserCache.saveUser(user);
            }
        });
    }
    /**
     * 登出
     */
    void logout(){
        HttpUtil.logout(new Callback(){
            @Override
            void onSuccess(){
                //登出完成将user从缓存清除
                UserCache.clearUser();
            }
        });
    }
}

public class UserCache {
    static void saveUser(User user){
        Cache.getInstance().saveUser(user);
    }
    static void clearUser(){
        Cache.getInstance().clearUser();
    }
}

其中saveUser和clearUser被拿到单独的缓存类实现,而不是直接实现在UserManager里,单一职责的目的就是使其减少耦合,更容易维护。

开闭原则

一个模块或类应该对拓展开放,对修改关闭。就是说不应该去改变一个现有的类,而可以去给这个类进行拓展增加功能。举个例子,一个手机生产的时候是要有手机屏幕的,如果你想要加个手机壳自己加就行了,但是不应该把我的屏幕给拆了,而在代码上就要用到继承或接口来实现。

里氏替换原则

凡是父类出现的地方,子类都应该能替换父类,而不会出现错误和异常,也就是保证子类的行为和属性要与父类一致,可以对父类进行拓展补充。听上去其实也是对开闭原则的延伸。假设在用户缓存中,现有的UserCache是将用户信息缓存到SD卡,那么现在如果需求变更为除了缓存到SD卡外还要缓存到sp中一份。那么这个时候只要集成UserCache重写相关方法即可,而不是直接去修改UserCache,而在调用端直接替换UserCahe的初始化(其实应该将缓存抽象成接口,这个后面会说到)。

// 调用端
UserCache userCache = new UserCache();

public class UserCache {
    void saveUser(User user){
        Cache.getInstance().saveUser(user);
    }
    void clearUser(){
        Cache.getInstance().clearUser();
    }
}

修改为:

// 调用端
SpAndSdCache userCache = new SpAndSdCache();

public class SpAndSdCache extends UserCache{
    @Override
    void saveUser(User user) {
        super.saveUser(user);
        // 加入sp缓存
    }
    @Override
    void clearUser() {
        super.clearUser();
        // 清除缓存
    }
}

依赖倒置原则

高层模块不应该依赖于底层模块,而都应该依赖于抽象。抽象不应该依赖于细节,细节应该依赖于抽象。所谓的“要面向接口编程,不要面向实现编程”。

依赖倒转原则要求我们在程序代码中传递参数时或在关联关系中,尽量引用层次高的抽象层类,即使用接口和抽象类进行变量类型声明、参数类型声明、方法返回类型声明,以及数据类型的转换等,而不要用具体类来做这些事情。为了确保该原则的应用,一个具体类应当只实现接口或抽象类中声明过的方法,而不要给出多余的方法,否则将无法调用到在子类中增加的新方法。

比如上面的UserManager用户管理类中,直接获取UserManager实例调用login和logout方法,这?我们的?层模块,即登录界?也是?个细节实现类,该登录功能依赖的是UserManager这个实体类,即依赖了细节没有依赖抽象。?旦UserManager更改,或者我们实?其他?户管理类,那么这?登录?法都要全部进?改动。对此,我们可以将对UserManager 的依赖改为依赖抽象:

public class UserManager implements IUserManager{
    /**
     * 登录
     */
    @Override
    public void login(){
        HttpUtil.login();
    }
    /**
     * 登出
     */
    @Override
    public void logout(){
        HttpUtil.logout();
    }
}

调用方:
IUserManager userManager = UserManager.getInstance();
userManager.login();

依赖倒置原则的实现方法:

  • 每个类尽量提供接口或抽象类,或者两者都具备。
  • 变量的声明类型尽量是接口或者是抽象类。
  • 任何类都不应该从具体类派生。
  • 使用继承时尽量遵循里氏替换原则。

接口隔离原则

一个模块对另一个模块的依赖应该建立在最小的接口上,它不应该依赖不需要的接口,不同的功能要抽象成不同的接口。当一个接口过于庞大时就要考虑是否要拆分成不同模块的接口,其实这也是单一职责的补充。比如客户端可以使用sp键值对缓存和SD卡缓存,可能会这样设计接口:

public interface ICacheManager {
    // SD卡缓存
    void sdCache();
    // sp缓存
    void spCache();
}

//调用方
public class UserManager implements ICacheManager{
    @Override
    public void sdCache() {
    }
    @Override
    public void spCache() {
    }
}

这里就存在缺陷,如果一个调用方是需要sp缓存或者SD卡缓存的话是不需要去实现另一个接口的。为了符合接隔离原则可以这样拆分为两个接口,调用方需要哪个方法实现对应接口即可:

// SD卡缓存
public interface ISdCacheManager {
    void sdCache();
}
// sp缓存
public interface ISpCacheManager {
    void spCache();
}

// 调用方
public class UserManager implements ISdCacheManager,ISpCacheManager{
    @Override
    public void sdCache() {

    }
    @Override
    public void spCache() {

    }

接口隔离原则的实现方法

  • 接口尽量小,但是要有限度。一个接口只服务于一个子模块或业务逻辑。
  • 为依赖接口的类定制服务。只提供调用者需要的方法,屏蔽不需要的方法。
  • 了解环境,拒绝盲从。每个项目或产品都有选定的环境因素,环境不同,接口拆分的标准就不同深入了解业务逻辑。
  • 提高内聚,减少对外交互。使接口用最少的方法去完成最多的事情。

迪米特法则

也称最小知法则,一个模块应该减少对其他模块的依赖,减少耦合。比如我们设计了用户管理类UserManager用来管理登录,登出等操作拱调用端调用,但是具体的登录登出中的写入,清空用户缓存功能调用端是不了解的。

总结

其实所有的设计原则及设计模式都是为了使系统能够更加易于维护,拓展。减少耦合,提高开发效率,使代码易读性更高。我们在编程时,要时刻以这些原则约束自己,养成良好的编码习惯。

关于设计模式的相关视频讲解可移步https://www.bilibili.com/video/BV1WL411s7zj/

作者:单总不会亏待你
链接:https://juejin.cn/post/7013357097635020808

  移动开发 最新文章
Vue3装载axios和element-ui
android adb cmd
【xcode】Xcode常用快捷键与技巧
Android开发中的线程池使用
Java 和 Android 的 Base64
Android 测试文字编码格式
微信小程序支付
安卓权限记录
知乎之自动养号
【Android Jetpack】DataStore
上一篇文章      下一篇文章      查看所有文章
加:2021-10-02 14:59:33  更:2021-10-02 15:01:15 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/23 20:10:44-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码