设计原则与设计模式

76 阅读10分钟

面向对象六大设计原则

  1. 单一职责原则:每个类尽量功能单一。
  2. 开闭原则:尽量开放扩展,封闭修改。
  3. 里氏替换原则:父类出现的地方子类都可以无代价替换,但是子类出现的地方父类不行 “抽象”。
    public class Window{
        //这里父类出现的地方,子类TextView,和ImageView都可以传进来且都可以正常使用
        public void show(View view){
          view.draw();
        }
    }
    public abstract class View{
      void draw();
      void measure(int width,int height){
          //测量大小
      }
    }
    public class TextView extends View{
        void draw(){
            //自己的逻辑
        }
    }
    public class ImageView extends View{
        void draw(){
            //自己的逻辑
        }
    }
    
  4. 依赖倒转原则:上层模块不应依赖下层模块,抽象不应该依赖细节,细节一共依赖抽象。模块间的依赖通过抽象发生,实现类之间不发生直接依赖关系,其依赖关系是通过接口或抽象类产生。
//内存缓存
    public interface ImageCache{
        public Bitmap get(String url);
        public void put(String url,Bitmap bmp);
    }
    
    public class MemoryCache implements ImageCache{
        private LruCache<Stringm,Bitmap> mMemoryCache;
        
        public MemoryCache(){
            //初始化缓存
        }
        
        @Override
        public Bitmap get(String url){
            return mMemoryCache.get(url);
        }
        
        @Override
        public void put(String url,Bitmap bmp){
            mMemoryCache.put(url,bmp);
        }
    }
    //sd卡缓存 DiskCache类
    public class  DiskCache implements ImageCache{
         //省略       
    }
    
    public class ImageLoader{
    //图片缓存类,依赖于抽象,并且有一个默认实现可以,
        ImageCache mCache=new MemoryCache();
        public void displayImage(String url,ImageView imageView){
            Bitmap bmp=mCache.get(url);
            //省略
        }
    }
    //设置需要的缓存策略
    public void setImageCache(ImageCache cache){
        this.mMemoryCache=cache;   
    }
  }
  1. 接口隔离原则:客户端不应该依赖它不需要的接口。一个类对另一个类的依赖应该建立在最小的接口上,从而避免过度耦合。

  2. 迪米特法则:一个对象应该对其他对象有最少的了解,对于被调用的对象,应该只给需要的内容。

23 种设计模式

一、创建型模式 5

提供实例化的方法,为适合的状况提供相应的对象创建方法。

  • 单例模式:全局一个实例
  • 简单工厂/工厂模式:抽象一个产品接口,一系列的实现接口的产品,让用户决定使用那个产品(只有一个车间,有个长生产一类规格的产品,比如只能生产电视)
  • 抽象工厂:类比于工厂的各个生产车间,每一条生产线都可以生产N种产品,每一条生产线一种抽象的产品规格(抽象的抽象,比如这个车间生产电视,那个车间生产手机)
/**
 * 手机产品接口
 */
public interface IPhoneProduct {
    /**
     * 拨打电话
     */
    void actionCall();

    /**
     * 发送短信
     */
    void actionSMS();
}

/**
 * 路由器产品接口
 */
public interface ICarProduct {

    /**
     * 开车
     */
    void openCar();
}

/**
 * 工厂抽象
 */
public interface IProductFactory {

    /**
     * 手机生产车间
     * @return
     */
    IPhoneProduct producePhone();

    /**
     * 汽车生产车间
     * @return
     */
    ICarProduct produceCar();
}
//小米手机生产线
public class XiaomiPhone implements IPhoneProduct{
    //省略
}
//小米汽车生产线
public class newXiaomiCar implements ICarProduct{
    //省略
}
/**
 * 小米工厂
 */
public class XiaomiProductFactory implements IProductFactory{
    @Override
    public IPhoneProduct producePhone() {
        System.out.println("==>小米手机");
        return new XiaomiPhone();
    }

    @Override
    public ICarProduct produceCar() {
        System.out.println("==>小米汽车");
        return newXiaomiCar();
    }
}
  • 建造者模式[Builder]:

使用层面: 组装过程复杂,属性、步骤顺序影响结果的,构建对象过于复杂的,一般用建造者。

AlertDialog 就是典型的例子

  • 原型模式:

原型模式 通过一个对象的方法可以方便的克隆出另一个对象,一般用于创建新对象比较麻烦的情况。

原则 只要可以使用原对象可以很方便的创建新对象就是,不用局限于非要使用Cloneable

    • 原型模式克隆:浅克隆、深克隆

浅克隆:创建一个新对象,新对象的属性和原来对象完全相同,对于非基本类型属性,仍指向原有属性所指向的对象的内存地址。
深克隆:创建一个新对象,属性中引用的其他对象也会被克隆,不再指向原有对象地址。

    • 浅拷贝
//原型对象 - 学生
public class Student implements Cloneable{

    private String className; //班级 
    private Person person; //p
    
    @Override 
    protected Student clone() throws CloneNotSupportedException { 
        //此处Student对象copy了一份,person对象仍然指向源对象,
        return (Student)super.clone();
    }
}
public class Person{
    
    private String name; //名字
    private int age;//年龄
}

    • 深拷贝 (内部牵扯到的对象都需要进行拷贝)
//原型对象 - 学生
public class Student implements Cloneable{

    private String className; //班级 
    private Person person; //p
    
    @Override 
    protected Student clone() throws CloneNotSupportedException { 
        //此处Student对象copy了一份,person对象仍然指向源对象,
        Student std=  (Student)super.clone();
        //内部person对象也拷贝一份
        std.person=this.person.clone();
        return std;
    }
}
public class Person implements Cloneable{
    
    private String name; //名字
    private int age;//年龄
        
    @Override 
    protected Person clone() throws CloneNotSupportedException { 
        //person对象的拷贝
        return (Person)super.clone();
    }
}

二、结构型模式 7

通常用来处理实体之间的关系,使得这些实体能够更好地协同工作

  • 外观模式【Facade】

    一般用于SDK, 业务逻辑不需要别人知道,只开放需要的api给对方使用,只能看到外表。

  • 适配器模式【Adapter】

    将一个接口转换成客户希望的另一个接口,使接口不兼容的那些类可以一起工作,其别名为包装器

    adapter

  • 代理模式【Proxy】

    本质:生成代理类去代理原对象方法的调用。 静态代理(手动写代理类、APT生成代理类)、动态代理(内存插装性能损耗)

    ART 对于内存管理限制 12/24/48m(年轻(一等、二等)、老年) ,少用动态代理

    代理的延申:aspectj AOP,切点 切面

      • 1、写一套类去实现原对象所有方法调用转发(静态代理)
      • 2、内存插装 (有内存损耗):直接加载到内存 如系统提供的 (动态代理,本质还是静态,只是android内部自己生成了代理内直接加载到内存了) Proxy.newProxyInstance()
      • 3、APT (编译时生成代理类)使用APT自己生成对应的代理类并且加载到内存使用 APT 、Classloader
  • 装饰模式【Decorator】

    定义:动态的给对象添加一些额外的职责。就增加功能来说,装饰器生成子类更灵活。

  • 桥接模式【Bridge】

    解释:一个类存在两个独立变化的维度,且这俩个维度都需要进行扩展

    电器、和开关是两个维度的东西,有各种各样的电器,有开、关或者其他功能,但是电器都有这些功能,则可以把开关和电器融合起来就叫桥接

  • 组合模式【Composite】

    使用:业务中存在树形结构设计 ,自己是文件,自己又持有下级,文件结构处理, 文件夹下有文件和文件夹,文件夹下有有... 物以类聚

    结构形式:链表

    例子:View ViewGroup

  • 享元模式【Flyweight】

    运享元模式的核心是 对象池 , 使用对象时 , 先从对象池中获取对象 , 如果对象池中没有 , 创建一个 , 放入对象池 , 然后再从对象池中获取 ; ( 只能从对象池中拿对象 , 不能自己创建 )

    • 典型用例
    //利用消息池 获取可用的Message对象,
    Message.obtain();
    //系统服务利用享元思想提前把所有需要的服务都放入到map中
    Context.getSystemService
    public final class SystemServiceRegistry {
    private static final String TAG = "SystemServiceRegistry";
    
    /** @hide */
    public static boolean sEnableServiceNotFoundWtf = false;
    
    // Service registry information.
    // This information is never changed once static initialization has completed.
    private static final Map<Class<?>, String> SYSTEM_SERVICE_NAMES =
            new ArrayMap<Class<?>, String>();
    //服务存储点
    private static final Map<String, ServiceFetcher<?>> SYSTEM_SERVICE_FETCHERS =
            new ArrayMap<String, ServiceFetcher<?>>();
    private static final Map<String, String> SYSTEM_SERVICE_CLASS_NAMES = new ArrayMap<>();
    //省略    
    }
    
三、行为型模式 11

目的 通过特别的写法,达成某个业务场景下的具体业务诉求

  • 模板方法模式【Template Method】

    目的:提供一个可用的模板给用户使用,将多个类共同的方法步骤抽象出来。

        /**
       * author : Administrator
       * time   : 2024/2/7 10:05
       * desc   :机器
       */
      public abstract class Machine {
          public void powerOn(){
              //开机
          }
    
          public void checkHardware(){
              //硬件检测
          }
    
          public void powerOff(){
              //关机
          }
    
          //相同逻辑
          public void doAction(){
              powerOn();
              checkHardware();
              powerOff();
          }
    
      }
    
      class HotelTerminal extends Machine{
    
          @Override
          public void checkHardware(){
              //酒店自助机验证
          }
      }
    
      class ComputerTerminal extends Machine{
    
          @Override
          public void checkHardware(){
              //电脑硬件检测
          }
      }
    
    
  • 观察者模式【Observer】

    目的 当数据或者业务变化能够更好的通知到所有注册了监听的对象或方法

      • 实现
     //在被观察者中注册存储已经注册过的观察者
    protected List<Observer> observers = new ArrayList<>();
    //添加观察者
    public void addObserver(Observer obs){
        observers.add(obs);
    }
    //删除观察者
    public void deleteObserver(Observer obs){
        observers.delete(obs);
    //通知观察者,由子类采用不同的方法实现
    public void notifyObserver(){
    }
    
  • 状态模式【State】

    目的 也是方案上的替换,他的动态替换需要一个核心的依据 依据当时的某一个状态选择选择方案 if else switch 如:播放器的状态

  • 策略模式【Strategy】

    目的 为了某个业务下需要有多套算法来支撑整个业务体系的一种灵活的替换方案 为用户提供多种选择 核心 有多套计算方案可以更替执行状态下应用多态实现功能的动态替换 动画插值器,线性,非线性动画。。。。

  • 职责链模式【Chain of Responsibility】

    场景 需要一步一步实现业务 业务的链表形式

    钉钉请假业务 需要层层领导审批,且不同的业务需要审批的人员、领导的深度不一样

  • 命令模式【Command】

    android 中一般用的少

    作用:对原业务进行增强 ,如 游戏业务需要对操作按键进行回溯需要在操作上下增加相关的记录诉求

    public class Action{
        
        piublic void toLeft(){
            //业务
        }
     
        piublic void toRight(){
            //业务
        }
    }
    
    //命令模式 业务增强
    public class Command{
        Action action;
         
        piublic void toLeft(){
            //功能增强诉求
            action.toLeft();
            //其他业务指令
        }
     
        piublic void toRight(){
            //业务
        }
    
    }
    
    
  • 解释器模式【Interpreter】

    android 中一般用的少,一般用用于自定义协议 自定义协议包,的自定义解释 自己定义一种格式的的解释器

    //计算值
     "123+321-213+223"
     //采用解释器模式
     //解释数字
     public class NumberInterpreter{
         private String num;
         public NumberInterperter(String num){
             this.num=num;
         }
         public int interpreter(){
            Integer.parseInt(num)
         }
     }
     //解释运算符号
     public class OperatorInterpreter{
         private String operator;
         public NumberInterperter(String operator){
             this.operator=operator;
         }
         public int interpreter(int a,int b){
            //根据operator运算符号进行int相关计算
            //省略
         }
     }
     
    
  • 访问者模式【Visitor】

    实现方式:把一个对象传给另一个对象去使用

    使用目的:项目重构或者使用不好修改的API或者升级时,可以自己单起一个类实现自己的逻辑调用原API方法实现原来的功能(eg:在原来的基础上增加一个小功能)

    源码中: 在APT中有使用到

      public interface Folder {
          //需要调用File方法,你把file传递给我调用
          void visit(File file);
    
      }
      public class WorkFolder implements Folder{
      //这里是具体的实现
          @Override
          public void visit(File file) {
          //实现自己的逻辑
          
          //调用file的逻辑,切没动file的逻辑
              if(file instanceof WorkFile){
                  System.out.println("[工作文件夹]下,已找到  "+ file.getName());
              }
          }
       }
       
      //APT 中生成 产物类(三方sdk bufferknife原理)
      public class MainActivity$InjectAdapter implements InjectAdapter<MainActivity>{
          public void injects(MainActivity target){
              target.findViewById("注解处理器获取到的id的值");
          }
      }hui'su
      
    
  • 中介者模式【Mediator】

和事佬,把大家统一到一起,一台电脑主板中介者统一CUP、内存、显卡、IO设备一起干活。

目的:使复杂的网状逻辑变为心形逻辑,由一个对象统一调配,降低复杂度

  • 备忘录模式【Memento】:FrameWork源码重点梳理

目的 业务备份、存档 后悔药

方案 内存、文件存储.. 数据恢复

onsaveInstanceState

  • 迭代器模式【Iterator】

iterator,迭代器(Iterator)模式,又叫做游标(Cursor)模式,是为了给容器提供一个外部访问下一个的方式


/**
 * 抽象迭代器(Iterator)
 */
public interface PersonIterator extends Iterator<Person> {
   private List<Person> list=new ArrayList();
    private int index;
 
    public PersonListIterator(List<Person> list) {
        this.list = list;
        this.index = 0;
    }
 
    //检查是否还有下一个元素
    @Override
    public boolean hasNext() {
        return (index < list.size());
    }
 
    //返回下一个元素
    @Override
    public Person next() {
        if (!hasNext()) {
            throw new NoSuchElementException();
        }
        Person person = list.get(index);
        index++;
        return person;
    }
}