java设计模式(一)——单例模式、Builder模式、适配器模式

一、六大设计原则

  • 1.开闭原则
    对扩展开发,对修改关闭。
  • 2.里氏替换原则
    子类可以扩展父类的功能,但不能修改父类的功能。
  • 3.依赖倒置原则
    高层模块不应该依赖底层模块,两者都应该依赖抽象模块,抽象不应该依赖细节。
  • 4.单一职责原则
    规定一个类应该有且只有一个原因使它发生改变,否则该类应该被拆分。
  • 5.接口隔离原则
    一个类对另一个类的依赖应该建立在最小的接口上。
  • 6.迪米特法则
    也叫作最少知识原则
    只跟你的朋友交谈,不跟陌生人说话。也就是当两个程序无须直接通行,就不应该发生相互调用,可通过第三方调用。

二、单例模式

定义:确保某一个类只有一个实例,而且自行实例化冰箱整个系统提供这个实例。
使用场景:如果某个类的创建需要消耗系统过多的资源,或者整个系统就只需要某个类的一个对象。这样就可以使用单例模式。
单例模式的几个关键点:

  • 构造函数不对外开放
  • 通过一个静态方法或者枚举返回单例对象
  • 确保单例对象有且只有一个,尤其是多线程环境下
  • 确保单例对象对象在反序列化时不会重新构建新的对象

单例中比较简单的写法有懒汉式单例、饿汉式单例,不过这两个已经不推荐使用,这里不再赘述了。这里说说用的比较多的几种单例写法。

1.Double Check Look(DCL)实现单例
/**
 * double check lock实现单例
 */
public class Singleton {
    private static volatile Singleton instance;
    private Singleton(){}
    public static  Singleton getInstance(){
        if(instance == null){
           synchronized (Singleton.class){
               if(instance == null){
                   instance = new Singleton();
               }
           }
        }
        return instance;
    }
}

由于多线程安全问题,这种方式进行了两次判空,还增加了volatile 关键字,保证instance == null的操作都从主内存中读取。这种方式在第一次获取单例对象时耗时一点,之后的获取,效率比较高。但在单例对象唯一性方面,在某些情况还是会失效。

2.静态内部类实现单例
/**
 * 静态内部类实现单例
 */
public class Singleton {
    private Singleton(){}
    public static  Singleton getInstance(){
        return SingletonHolder.instance;
    }

    private static class SingletonHolder{
        private static final Singleton instance = new Singleton();
    }
}

这种方式当第一次调用Singleton 时不会初始化单例对象,只有当第一次调用getInstance时才会初始化对象,这样既保证了对象的延迟加载 ,也保证了对象的唯一性 。所以这种方式是推荐的单例写法。

以上两个两种方式都存在一个相同的问题,就是反序列化的时候,都有可能会生成新的对象,如果要解决这个问题,可以在类中加入以下代码

 private Object readResolve() throws ObjectStreamException{
        return instance;
 }

就是在readResolve方法中将对象单例对象返回回去,避免默认创建新的对象。
除了以上两种方式,还有枚举实现单例方式,和容器实现单例方式。

/**
     * 枚举实现单例
     */
    public enum SingletonEnum{
        INSTANCE;
        public void doSomething(){
            // TODO: 2020/10/11
        }
    }

容器实现单例就是就利用容器将单例对象存放起来,用时直接从容器里面取,这种方式可以管理多个类型的单例对象,在使用时用统一的接口,可以降低用户的使用成本降低了代码的耦合度。

三、Builder模式

定义:将一个复杂的对象与它的表现分离,使得同样的构建过程可以创建不同的表现。
使用场景

  • 相同的方法,不同执行顺序,产生不同的事件结果时。

  • 多个部件,都可以装配到一个对象中,但产生的运行结果又不相同时。

  • 对象类非常复杂,构建顺序不同会产生不同的作用。

    Builder模式有三个主要角色

    • 产品对象
    • Builder类,拥有产品对象的实例,负责将从Director对象收集的产品信息赋值到产品对象上。
    • Director类,构造函数会传入Builder对象,负责从用户端收集产品信息,Director将用户传入的产品属性信息传入到Builder对象。

四、适配器模式

定义:是原本两个不同类的对象,通过适配,变成能相互调用的模式。
例如,英国人只能讲英语,日本人只能说日语,如何让英国人说出日语呢?
适配器模式可分为对象适配器和类适配器两种,类适配器的适配器和适配者是 继承关系,而对象适配器则是引用关系。
下面用代码简单说明下适配器的写法:

1.对象适配器模式写法
注意:对象类型的适配者类型可以是接口或者是具体的类。

/**
 * 英国人
 */
public class English {
    void speakEnglish(String string){
        System.out.println("英国人"+string);
    }
}
/**
 * 日本人
 */
public class Japanese {
    void speakJapanese(String string){
        System.out.println("日本人"+string);
    }
}
/**
 * 翻译角色的适配器
 */
public class Translator extends Japanese {//翻译官与日本人是继承关系
    private English mEnglish = new English(); 
    public Translator(English english){//翻译官需要引用英国人的对象
        this.mEnglish = english;
    }

    @Override
    public void speakJapanese(String str) {
        mEnglish.speakEnglish(str);//翻译官在这里偷梁换柱
    }
}
/**
 * 客户端使用代码
 */
public class MyClass {

    public static void main(String[] args) {
        English english = new English();
        Translator translator = new Translator(english);
        translator.speakJapanese("说日语");
    }

}

输出结果

英国人说日语

2.类适配器模式写法:

注意:类适配器模式的适配者只可以是接口。

/**
 * 日本人接口
 */
public interface JapaneseInterface {
    void speakJapanese(String string);
}

/**
 * 翻译角色的适配器
 */
public class Translator2 extends English implements JapaneseInterface{
    @Override
    public void speakJapanese(String string) {//外面翻译官调用说日语的方法,实际调用说英语
        speakEnglish(string);//直接在这里偷梁换柱
    }
}
/**
 * 客户端使用代码
 */
public class MyClass {

    public static void main(String[] args) {
        Translator2 translator2 = new Translator2();
        translator2.speakJapanese("说日语");
    }

}

输出结果:

英国人说日语
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值