Java设计模式

设计模式

参考:菜鸟教程

六大原则

  • 开闭原则(Open Close Principle): 一个软件实体应当对扩展开放,对修改关闭。开闭原则也是其他五个原则的基石
  • 单一职责原则(Single Responsibility Principle):一个类只负责一个功能领域中的相应职责,或者可以定义为:就一个类而言,应该只有一个引起它变化的原因。
  • 里氏代换原则(Liskov Substitution Principle):所有引用基类(父类)的地方必须能透明地使用其子类的对象。
  • 依赖倒置原则(Dependence Inversion Principle):程序要依赖于抽象接口,不要依赖于具体实现。
  • 接口隔离原则(Interface Segregation Principle):使用多个专门的接口,而不使用单一的总接口,即客户端不应该依赖那些它不需要的接口。
  • 迪米特法则(Law of Demeter, LoD)(最少知道原则):一个软件实体应当尽可能少地与其他实体发生相互作用。

设计模式solid六大原则

三大分类

创建型模式:

工厂方法模式、抽象工厂模式、单例模式、建造者模式、原型模式。

结构型模式:

适配器模式、装饰器模式、代理模式、外观模式、桥接模式、组合模式、享元模式。

行为型模式:

策略模式、模板方法模式、观者模式、迭代子模式、责任链模式、命令模式、备忘录模式、状态模式、访问者模式、中介者模式、解释器模式。

创建型模式

单例模式

保证在同一个进程只拥有一个实例

  • 单例类只能有一个实例。
  • 单例类必须自己创建自己的唯一实例。
  • 单例类必须给所有其他对象提供这一实例。

实现

  • 持有一个该例的全局静态变量 public static Earth earth;
  • 将构造方法私有 private
  • 创建外部调用方法返回实例

饿汉式:线程安全,但是在类加载时就初始化,浪费内存,容易产生垃圾对象

public class Singleton {  
    private static Singleton instance = new Singleton();  
    private Singleton (){}  
    public static Singleton getInstance() {  
    return instance;  
    }  
}

懒汉式:加上synchronized 才能实现线程安全,但是效率比较低

public class Singleton {  
    private static Singleton instance;  
    private Singleton (){}  
    public static synchronized Singleton getInstance() {  
    if (instance == null) {  
        instance = new Singleton();  
    }  
    return instance;  
    }  
}

最佳实现:双重校验锁
双重校验是为了防止第一个判定未获取到锁时间,判断为空后失去被CPU调度走了造成单例失效

public class Singleton {  
    private volatile static Singleton singleton;  
    private Singleton (){}  
    public static Singleton getSingleton() {  
    if (singleton == null) {  
        synchronized (Singleton.class) {  
        if (singleton == null) {  
            singleton = new Singleton();  
        }  
        }  
    }  
    return singleton;  
    }  
}

工厂模式

抽象统一的接口,将类的创建移到工厂类当中,只要告诉工厂类需要什么东西,就直接拿到工厂“生产”的产品,而不需要关心具体的创建过程

菜鸟教程

使用步骤:

  • 抽象对象统一接口,对不同的类有各自自己的实现
  • 创建工厂类,根据传入不同的标识,返回不同的实现对象
  • 拿到实现的对象,接口

建造者模式

  • 当一个对象由若干个基本对象组成,但是产出的结果是相同的
  • 产品内部调用顺序不同会导致不同的结果
  • 初始化对象非常复杂,有很多个构造方法或者很多参数由默认值时

使用步骤:

  • 抽象化产品类
  • 抽象Builder,规范产品组建
  • 创建具体类的Builder
  • 创建Director类,负责构造具体的产品类

链式多参数调用:参考okhttp源码Request的Builder

推荐阅读

原型模式

当从数据库等取出相似对象需要耗费大量时间时,可以通过预先加载好对象,然后通过clone方法,快速的得到一个所需对象。
使用场景:

  • 需要耗费较大的资源去创建一个重复对象
  • 与工厂模式进行配合

菜鸟教程

行为型模式

策略模式

使用场景

  • 当多个场景的算法、行为十分相似,造成大量的if…else…难以维护;又或者有多个类,他们之前的区别只是行为不同;
  • 可以用于解耦代码

角色

  • 设计行为接口,例如登录: ILoginStrategy
  • 具体的实现类,例如WXLogin、QQLogin等
  • 策略环境类:LoginContextStrategy,持有具体行为类(例如WXLogin),根据实际场景调用行为类具体实现方法

实例参考:

责任链模式

责任链模式就是将接收者对象连成一条链,并在该链上传递请求,直到有一个接收者对象处理它。通过让更多对象有机会处理请求,避免了请求发送者和接收者之间的耦合。

  • 设计统一接口(处理、设定下一级处理对象)
  • 工厂类,组装责任链
  • 发起调用,根据具体逻辑依次调用直到符合条件

实例:

  • 参考
  • okhttp源码的拦截器链

结构型模式

适配器模式

使用场景

需要将一个接口转换成客户需要的另一个接口,使原本由于接口不兼容而不能一起工作的类可以一起工作,提高类的复用

装饰者模式

使用场景:

需要拓展某个类的功能,同时不影响原有类;
在不想增加很多子类的情况下扩展类。

特点

装饰模式是继承的一个替代模式,装饰模式可以动态扩展一个实现类的功能。

例子:
菜鸟教程

外观模式

使用场景:

为一组相似的行为,进行一个统一的封装,调用者不需要知道内部如何实现,简化逻辑、减少错误;

  • 降低访问复杂系统的内部子系统时的复杂度,简化客户端与之的接口。
  • 为复杂的模块或子系统提供外界访问的模块,且子系统相对独立
  • 在层次化结构中,可以使用外观模式定义系统中每一层的入口。

常用于SDK或者三方开源库为调用者提供一个统一的入口

代理模式

作用描述:

在不改变原对象的前提下,提供一种方式操作原对象(访问一个类时做一些控制)

分类:分为静态代理和动态代理(代码编译时不知道具体是哪个类)
原理:JDK动态代理是基于Java的反射机制实现的原理参考这篇,并且只能代理接口,JDK为帮我们生成一个继承于proxy类和代理接口的代理类
实例

public interface IEat {
    String eatSomething(String food);
}

// 实现类
public class EatImpl implements IEat {
    @Override
    public String eatSomething(String food) {

        int time = (int) (Math.random() * 1000);

        return String.format("Eat %s with %d second",food,time);
    }
}

// 静态代理
public class EatProxy implements IEat {

    IEat iEat;

    public EatProxy(IEat iEat) {
        this.iEat = iEat;
    }

    @Override
    public String eatSomething(String food) {

        System.out.println("do something before eating");

        return iEat.eatSomething(food);
    }
}

// 动态代理实现
public class EatHandler implements InvocationHandler {

    private Object object;

    public EatHandler(Object object) {
        this.object = object;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {

        System.out.println("do something before eating in EatHandler");
        
        Object result = method.invoke(object,args);
        return result;
    }
}

// 测试类
public class ProxyTest {

    public static void main(String[] args) {

        IEat iEat = new EatImpl();
        EatProxy eatProxy = new EatProxy(iEat);

        IEat eatHandler = (IEat) Proxy.newProxyInstance(iEat.getClass().getClassLoader(),iEat.getClass().getInterfaces(),new EatHandler(iEat));

        System.out.println(eatProxy.eatSomething("meet"));
        System.out.println( eatHandler.eatSomething("Vegetables"));
        
    }
}

// 输出结果
do something before eating
Eat meet with 842 second
do something before eating in EatHandler
Eat Vegetables with 333 second

享元模式

作用描述:

如果在一个系统中存在多个相同的对象,那么只需要共享一份对象的拷贝,而不必为每一次使用都创建新的对象。目的是提高系统性能,避免重复创建对象

和单例模式区别
单例模式保存的是一个单个类的状态,享元模式是共享对象,避免大量创建重复对象

三个角色

  • 抽象外部键值接口,用于标识同一类别
  • 享元工厂,用来获取对象
  • 具体享元对象

Book接口和实现类


   // IBook接口 抽象出书名
   public interface IBook { void borrow(); }

   // 具体实现类 省略 get、set方法
    private String name; 
    private String mark;

    public Book(String name) {
        this.name = name;
    }

    @Override
    public void borrow() {
        System.out.println("borrow book ,name : " + name);
    }
    @Override
    public String toString() {
        return "阅读的书本名:" + name +
                " 笔记内容:" + mark;
    }

享元工厂类:

public class BookFactory {

    private static volatile BookFactory sInstance;
    private HashMap<String,Book> bookPool = new HashMap<>();

    public static BookFactory getsInstance() {

        if (sInstance == null){
            synchronized (BookFactory.class){
                if (sInstance == null){
                    sInstance = new BookFactory();
                }
            }
        }
        return sInstance;
    }

    public Book getBook(String name){

        if (bookPool.containsKey(name)){
            System.out.println("存在" + name + ",直接借出");
            return bookPool.get(name);
        }

        System.out.println("书本:" + name + " 不存在,创建并返回");
        Book book = new Book(name);
        bookPool.put(name,book);
        return book;
    }

    public int getBookListSize(){
        return bookPool.size();
    }
    
}

测试类以及输出

public class BookMainTest {

    public static void main(String[] args) {

        BookFactory bookFactory = BookFactory.getsInstance();

        Book book = bookFactory.getBook("Java从入门到放弃");
        bookFactory.getBook("Android从入门到放弃");
        bookFactory.getBook("第一行代码");
        bookFactory.getBook("第二行代码");
        bookFactory.getBook("第三行代码");

        // 做笔记
        book.setMark("小明的java读书笔记");
        System.out.println(book.toString());

        // 被别人借走了,又做了笔记
        bookFactory.getBook("第二行代码");
        Book book1 = bookFactory.getBook("Java从入门到放弃");
        book1.setMark("小红的java读书笔记");
        System.out.println(book.toString());

        System.out.println("图书馆存在" + bookFactory.getBookListSize() + "本书");

    }
}

// 输出:
书本:Java从入门到放弃 不存在,创建并返回
书本:Android从入门到放弃 不存在,创建并返回
书本:第一行代码 不存在,创建并返回
书本:第二行代码 不存在,创建并返回
书本:第三行代码 不存在,创建并返回
阅读的书本名:Java从入门到放弃 笔记内容:小明的java读书笔记
存在第二行代码,直接借出
存在Java从入门到放弃,直接借出
阅读的书本名:Java从入门到放弃 笔记内容:小红的java读书笔记
图书馆存在5本书

桥接模式

通过定义抽象
参考这篇文章

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值