温馨提示×

温馨提示×

您好,登录后才能下订单哦!

密码登录×
登录注册×
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》

常用设计模式 Java 实现

发布时间:2020-08-21 12:02:45 来源:网络 阅读:425 作者:灰白世界 栏目:编程语言

设计模式分类

创建型模式,共五种:工厂方法模式、抽象工厂模式、单例模式、建造者模式、原型模式。

结构型模式,共七种:适配器模式、装饰器模式、代理模式、外观模式、桥接模式、组合模式、享元模式。

行为型模式,共十一种:策略模式、模板方法模式、观察者模式、迭代子模式、责任链模式、命令模式、备忘录模式、状态模式、访问者模式、中介者模式、解释器模式

设计模式六大原则

  • 开闭原则:开闭原则就是说对扩展开放,对修改关闭
  • 里氏代换原则:任何基类可以出现的地方,子类一定可以出现,只有当衍生类可以替换掉基类,软件单位的功能不受到影响时,基类才能真正被复用,而衍生类也能够在基类的基础上增加新的行为
  • 依赖倒转原则:面对接口编程,依赖于抽象而不依赖于具体
  • 迪米特法则:一个实体应当尽量少的与其他实体之间发生相互作用,使得系统功能模块相对独立
  • 合成复用原则:原则是尽量使用合成、聚合的方式,而不是使用继承

单例模式

常用设计模式 Java 实现

什么是单例?

保证一个类只会创建一个实例

应用场景:

  • Winodw 任务管理器
  • Windows 回收站
  • 网站的在线人数计数器
  • 应用程序的日志应用
  • Web 应用配置对象的读取
  • 数据库连接池
  • 线程池
  • 文件系统
  • HttpApplication

运行时动态获取类信息

饿汉式

/**
 * 饿汉式:
 *  类初始化时,会立即加载对象,线程天生安全,效率高
 */
public class User {
    // 存在方法区,不会回收
    private static User user = new User();
    private User() {
    }

    public User getInstance() {
        return user;
    }

懒汉式

/**
 * 懒汉式:
 *  类初始化时,不会真正创建对象,只有使用时才真正创建对象
 */
public class User {

    private static User user;

    private User() {
    }

    public static synchronized User getInstance() {
        if (user == null)
            user = new User();
        return user;
    }
}

静态内部类

/**
 * 静态内部类:
 *  兼顾了懒汉模式的内存优化(使用时才初始化)以及饿汉模式的安全性(不会被反射***)
 */
public class User {
    private User(){

    }

    static class SingletonClassInstance{
        private static final User user = new User();
    }

    public static User getInstance() {
        return SingletonClassInstance.user;
    }
}

枚举方式

/**
 * 枚举:
 *  枚举天生就是单例,从JVM提供保障单例,避免反射,缺点没有延迟加载
 */
public class User {

    private User() {
    }

    public static User getInstance() {
        return SingletonUserEnum.INSTANCE.getInstance();
    }

    static enum SingletonUserEnum{
        INSTANCE;
        private User user;
        private SingletonUserEnum() {
            user = new User();
        }

        public User getInstance() {
            return this.user;
        }
    }
}

双重检验锁

/**
 * 双重检验锁:
 *  线程安全的单例模式
 */
public class User {
    private String userName;
    private volatile static User3 user3;

    private User(){

    }

    public User getInstance(){
        if (user == null) {
            synchronized (this) {
                if (user == null){
                    user = new User();
                }
            }
        }
        return user;
    }
}

如何防止反射漏洞***?

在类里面增加一个 flag,初始值为 false,创建对象后更改为 true,如果为 true,就抛出异常

如何选择单例创建方式?

需要延迟加载,选择静态内部类、懒汉式

不需要延迟加载,选择枚举类、饿汉式

多线程应用首选双重检验锁

工厂模式

常用设计模式 Java 实现

什么是工厂模式?

实现了创建者和调用者分离,工厂模式分为简单工厂、工厂方法、抽象工厂模式

应用场景:

  • 日志记录器:记录可能记录到本地硬盘、系统事件、远程服务器等,用户可以选择记录日志到什么地方
  • 数据库访问,当用户不知道最后系统采用哪一类数据库,以及数据库可能有变化时
  • 设计一个连接服务器的框架,需要三个协议,"POP3"、"IMAP"、"HTTP",可以把这三个作为产品类,共同实现一个接口

简单工厂

/**
 * 简单工厂相当于一个工厂有各种产品,用户无需知道具体产品的名称,只需要知道产品对应的参数即可
 * 缺点是类型过多不利于扩展维护 
 */
public class CarFactory {
    public static Car createrCar(String name) {
        if (name == null || name.equals(""))
            return null;
        if (name.equals("比亚迪"))
            return new BydCar();
        if (name.equals("吉利"))
            return new JiliCar();
        return null;
    }
}

工厂方法

/**
 * 核心工厂不在负责所有产品的创建,而是将具体实现交给子类
 */
public interface CarFactory {
    Car createrCar(String name);
}

class BydFactory implements CarFactory {

    @Override
    public Car createrCar(String name) {
        return new BydCar();
    }
}

class JiliFactory implements CarFactory {
    @Override
    public Car createrCar(String name) {
        return new JiliCar();
    }
}

抽象工厂模式

常用设计模式 Java 实现

什么是抽象工厂模式?

抽象工厂模式(Abstract Factory Pattern)是围绕一个超级工厂创建其他工厂

该超级工厂又称为其他工厂的工厂,这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式

在抽象工厂模式中,接口是负责创建一个相关对象的工厂,不需要显式指定它们的类,每个生成的工厂都能按照工厂模式提供对象

应用场景:

  • QQ 换皮肤,一整套一起换
  • 生成不同操作系统的程序
/**
 * 抽象工厂简单地说是工厂的工厂,抽象工厂可以创建具体工厂,由具体工厂来产生具体产品
 */
public interface Engine {
    void run();
}

class EngineA implements Engine{

    @Override
    public void run() {
        System.out.println("发动机转速快");
    }
}

class EngineB implements Engine {

    @Override
    public void run() {
        System.out.println("发动机转速慢");
    }
}

public interface Chair {
    void run();
}

class ChairA implements Chair {

    @Override
    public void run() {
        System.out.println("自动加热");
    }
}

class ChairB implements Chair {

    @Override
    public void run() {
        System.out.println("不能加热");
    }
}

public interface CarFactory {
    // 创建发动机
    Engine createEngine();
    // 创建座椅
    Chair createChair();
}

public class JiliFactory implements CarFactory{

    @Override
    public Engine createEngine() {
        return new EngineA();
    }

    @Override
    public Chair createChair() {
        return new ChairA();
    }
}

简单工厂、工厂方法、抽象工厂小结

  • 简单工厂:用来生产同一等级结构中的任意产品
  • 工厂方法 :用来生产同一等级结构中的固定产品
  • 抽象工厂 :用来生产不同产品族的全部产品

代理模式

常用设计模式 Java 实现

什么是代理模式?

代理模式可以控制对象的访问之前之后做一些操作,即 AOP

应用场景:

SpringAOP、事物原理、日志打印、权限控制、远程调用、安全代理

静态代理

/**
 * 由程序员创建或工具生成代理类的源码,再编译代理类
 * 所谓静态也就是在程序运行前就已经存在代理类的字节码文件,代理类和委托类的关系在运行前就确定了
 */
public interface IUserDao {
    void save();
}
public class UserDao implements IUserDao {
    public void save() {
        System.out.println("已经保存数据...");
    }
}
代理类
public class UserDaoProxy implements IUserDao {
    private IUserDao target;

    public UserDaoProxy(IUserDao iuserDao) {
        this.target = iuserDao;
    }

    public void save() {
        System.out.println("开启事物...");
        target.save();
        System.out.println("提交事物...");
    }
}

jdk 动态代理

/**
 * 是根据类加载器和接口创建代理类
 * 通过实现InvocationHandler接口创建自己的调用处理器
 * 通过为Proxy类指定ClassLoader对象和一组interface创建动态代理类
 * 通过反射机制获取动态代理类的构造函数
 * 通过构造函数创建代理类实例
 * 缺点必须提供接口
 */ 
public class InvocationHandlerImpl implements InvocationHandler {
    // 目标对象
    private Object target;

    public InvocationHandlerImpl(Object target) {
        this.target = target;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("开启事务");
        // 返回执行结果
        Object invoke = method.invoke(target, args);
        System.out.println("提交事务");
        return invoke;
    }

    public static void main(String[] args) {
        IUserDao userDao = new UserDaoImpl();
        InvocationHandlerImpl invocationHandler = new InvocationHandlerImpl(userDao);
        // 获得类加载器
        ClassLoader classLoader = userDao.getClass().getClassLoader();
        // 获得接口
        Class<?>[] interfaces = userDao.getClass().getInterfaces();
        IUserDao o = (IUserDao) Proxy.newProxyInstance(classLoader, interfaces, invocationHandler);
        o.add();
    }
}

cglib 动态代理

/**
 * 利用asm开源包,对代理对象类的class文件加载进来,通过修改其字节码生成子类来处理
 * 不需要提供接口
 */
public class CglibAutoProxy implements MethodInterceptor {
    // 目标对象
    private Object target;
    public Object getInstance(Object target){
        this.target = target;
        // 操作字节码生成虚拟子类
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(target.getClass());
        enhancer.setCallback(this);
        return enhancer.create();
    }

    @Override
    public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
        System.out.println("开启事务");
        Object invoke = methodProxy.invoke(target, objects);
        System.out.println("提交事务");
        return invoke;
    }

    public static void main(String[] args) {

        CglibAutoProxy cglibAutoProxy = new CglibAutoProxy();
        UserDaoImpl o = (UserDaoImpl) cglibAutoProxy.getInstance(new UserDaoImpl());
        o.add();
    }
}

CGLIB 动态代理与 JDK 动态区别?

JDK 动态代理是利用反射机制生成一个实现代理接口的匿名类,在调用具体方法前调用 InvokeHandler 来处理
而 CGLIB 动态代理是利用 asm 开源包,对代理对象类的 class 文件加载进来,通过修改其字节码生成子类来处理

Spring 中:

如果目标对象实现了接口,默认情况下会采用 JDK 的动态代理实现 AOP

如果目标对象实现了接口,可以强制使用 CGLIB 实现 AOP

如果目标对象没有实现了接口,必须采用 CGLIB 库,spring 会自动在 JDK 动态代理和 CGLIB 之间转换

JDK 动态代理只能对实现了接口的类生成代理,而不能针对类 。

CGLIB 是针对类实现代理,主要是对指定的类生成一个子类,覆盖其中的方法

因为是继承,所以该类或方法最好不要声明成 final ,final 可以阻止继承和多态

建造者模式

常用设计模式 Java 实现

什么是建造者模式?

是将一个复杂的对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示

工厂模式提供的是创建单个类的模式,而建造者模式则是将各种产品集中起来管理,用来创建复合对象

建造者模式包含以下几个角色:

Builder:给出一个抽象接口,以规范产品对象的各个组成成分的建造。这个接口规定要实现复杂对象的哪些部分的创建,并不涉及具体的对象部件的创建

ConcreteBuilder:实现Builder接口,针对不同的商业逻辑,具体化复杂对象的各部分的创建

Director:调用具体建造者来创建复杂对象的各个部分,在指导者中不涉及具体产品的信息,只负责保证对象各部分完整创建或按某种顺序创建

Product:要创建的复杂对象

应用场景:

  • 去肯德基,汉堡、可乐、薯条、炸鸡翅等是不变的,而其组合是经常变化的,生成出所谓的"套餐"
  • JAVA 中的 StringBuilder
public class Person {
    private String head;
    private String body;
    private String foot;
    // 省略get和set   
}

public interface PersonBuilder {
     void builderHead();
     void builderBody();
     void builderFoot();
     Person builderPerson();
}

public class ManBuilder implements PersonBuilder {
    private Person person;
    public ManBuilder(){
        person = new Person();
    }
    public void builderHead() {
        person.setHead("美国人头部 鼻子尖、长脸、蓝眼睛");
    }

    public void builderBody() {
        person.setBody("美国人 长得比较高、块头大");
    }

    public void builderFoot() {
        person.setFoot("美国人 腿长");
    }

    public Person builderPerson() {
        return person;
    }
}

public class PersonDirector {
    public Person creater(PersonBuilder personBuilder) {
        personBuilder.builderHead();
        personBuilder.builderBody();
        personBuilder.builderFoot();
        return personBuilder.builderPerson();
    }

    public static void main(String[] args) {
        PersonDirector personDirector = new PersonDirector();
        Person creater = personDirector.creater(new ManBuilder());
        System.out.println(creater);
    }
}

模板模式

常用设计模式 Java 实现

什么是模板模式?

完成一件事情,有固定的数个步骤,但是每个步骤根据对象的不同,而实现细节不同;就可以在父类中定义一个完成该事情的总方法,按照完成事件需要的步骤去调用其每个步骤的实现方法,每个步骤的具体实现,由子类完成

应用场景:

  • 在造房子的时候,地基、走线、水管都一样,只有在建筑的后期才有加壁橱加栅栏等差异
  • 西游记里面菩萨定好的 81 难,这就是一个顶层的逻辑骨架
  • spring 中对 Hibernate 的支持,将一些已经定好的方法封装起来,比如开启事务、获取 Session、关闭 Session 等,程序员不重复写那些已经规范好的代码,直接丢一个实体就可以保存
// 短信模板
public abstract class MsgTemplate {
    public void sendMsg() {
        addHeadLog();
        httpRequest();
        addHeadLog();
    }

    // 开始日志
    void addHeadLog() {
        System.out.println("调用运营商开始。。。");
    }

    abstract void httpRequest();

    void addFootLog() {
        System.out.println("调用运营商结束。。。");
    }
}

public class Liantong extends MsgTemplate {
    void httpRequest() {
        System.out.println("联通。。。");
    }
}

// 具体实现细节
public class Yidong extends MsgTemplate {
    void httpRequest() {
        System.out.println("移动。。。");
    }
}

public class ClientTemplate {
    public static void main(String[] args) {
        Yidong yidong = new Yidong();
        yidong.sendMsg();
    }
}

适配器模式

常用设计模式 Java 实现

什么是适配器模式

将一个类的接口转换成客户希望的另一个接口,适配器模式让那些接口不兼容的类可以一起工作

应用场景:

  • 美国电器 110V,中国 220V,就要有一个适配器将 110V 转化为 220V
  • 在 LINUX 上运行 WINDOWS 程序
  • JAVA 中的 jdbc
public interface JP110VInterface {
    void connect();
}

public class JP110VInterfaceImpl implements JP110VInterface {
    public void connect() {
        System.out.println("日本110V电源接口");
    }
}

public interface ZN220VInterface {
    public void connect();
}

public class ZN220VInterfaceImpl implements ZN220VInterface {
    public void connect() {
        System.out.println("中国220V电源接口");
    }
}

public class ElectricCooker {
    private JP110VInterface jp110VInterface;
    public ElectricCooker(JP110VInterface jp110VInterface) {
        this.jp110VInterface = jp110VInterface;
    }
    public void cook(){
        jp110VInterface.connect();
        System.out.println("开启做饭");
    }
}

public class PowerAdpater implements JP110VInterface {
    private ZN220VInterface zn220VInterface;
    public PowerAdpater(ZN220VInterface zn220VInterface) {
        this.zn220VInterface = zn220VInterface;
    }
    public void connect() {
        zn220VInterface.connect();
    }

    public static void main(String[] args) {
        ZN220VInterface zn220VInterface = new ZN220VInterfaceImpl();
        PowerAdpater powerAdpater = new PowerAdpater(zn220VInterface);
        ElectricCooker electricCooker = new ElectricCooker(powerAdpater);
        electricCooker.cook();
    }
}

外观模式

什么是外观模式?

外观模式门面模式,隐藏系统的复杂性,并向客户端提供了一个客户端可以访问系统的接口

应用场景:

  • 去医院看病,可能要去挂号、门诊、划价、取药,让患者或患者家属觉得很复杂,如果有提供接待人员,只让接待人员来处理,就很方便
  • JAVA 的三层开发模式
// 微信推送消息
public interface WeiXinSmsService {
    public void sendSms();  
}

public class WeiXinSmsServiceImpl implements WeiXinSmsService{
    public void sendSms() {
        System.out.println("发送微信消息");

    }
}

// 发送邮件
public interface EamilSmsService {
      public void sendSms();    
}

public class EamilSmsServiceImpl implements EamilSmsService{

    @Override
    public void sendSms() {
        System.out.println("发送邮件消息");
    }
}

// 支付宝推送消息
public interface AliSmsService {
    public void sendSms();
}

public class AliSmsServiceImpl implements AliSmsService {

    @Override
    public void sendSms() {
        System.out.println("支付宝发送消息...");
    }
}

public class Computer {
    AliSmsService aliSmsService;
    EamilSmsService eamilSmsService;
    WeiXinSmsService weiXinSmsService;
    public Computer() {
        aliSmsService = new AliSmsServiceImpl();
        eamilSmsService = new EamilSmsServiceImpl();
        weiXinSmsService = new WeiXinSmsServiceImpl();
    }

    public void sendMsg() {
        aliSmsService.sendSms();
        eamilSmsService.sendSms();
        weiXinSmsService.sendSms();
    }
}

public class Client {

    public static void main(String[] args) {
        new Computer().sendMsg();
    }
}

原型模式

常用设计模式 Java 实现

什么是原型模式?

原型模式可以用来克隆对象,被复制的实例就是原型,多用于创建复杂的实例,更节约性能。

应用场景:

  • 资源优化场景
  • 类初始化需要消化非常多的资源,这个资源包括数据、硬件资源等
  • 性能和安全要求的场景
  • 通过 new 产生一个对象需要非常繁琐的数据准备或访问权限,则可以使用原型模式
  • 一个对象多个修改者的场景
  • 一个对象需要提供给其他对象访问,而且各个调用者可能都需要修改其值时,可以考虑使用原型模式拷贝多个对象供调用者使用
  • 在实际项目中,原型模式很少单独出现,一般是和工厂方法模式一起出现,通过 clone 的方法创建一个对象,然后由工厂方法提供给调用者

浅复制和深复制:

只拷贝基本数据类型的数据,对于引用类型数据,仅复制引用,也就是说原型和复制后的对象共享一个变量,如果引用地址的数据发生改变,那么复制出来的对象也会发生改变,我们成为浅复制

深复制是在内存中开辟一块空间存放复制对象

public class Book implements Cloneable{
    private String title;
    private ArrayList<String> listImg = new ArrayList<String>();
    public Book() {
        super();
    }

    public String getTitle() {
        return title;
    }

    public void setTitle(String title) {
        this.title = title;
    }

    public List<String> getListImg() {
        return listImg;
    }

    public void setListImg(ArrayList<String> listImg) {
        this.listImg = listImg;
    }

    public void addImage(String img) {
        this.listImg.add(img);
    }

    public void showBook() {
        System.out.println("----------------start--------------");
        System.out.println("title:" + title);
        for (String img:listImg) {
            System.out.println("img:" + img);
        }
        System.out.println("-----------------end---------------");
    }

    @Override
    protected Object clone() throws CloneNotSupportedException {
        Book book = (Book) super.clone();
        book.listImg=(ArrayList<String>)this.listImg.clone();
        return book;
    }
}

public class Client {
    public static void main(String[] args) throws CloneNotSupportedException {
        Book book = new Book();
        book.setTitle("图书1");
        book.addImage("第一章");
        book.showBook();
        Book book1 = (Book) book.clone();
        book1.addImage("第二章");
        book1.showBook();
        book.showBook();
    }
}

策略模式

常用设计模式 Java 实现

什么是策略模式?

定义了一系列的算法,并将每一个算法封装起来,而且使它们还可以相互替换。策略模式让算法独立于使用它的客户而独立变化

应用场景:

  • 诸葛亮的锦囊妙计,每一个锦囊就是一个策略
  • 旅行的出游方式,选择骑自行车、坐汽车,每一种旅行方式都是一个策略
package com.kernel.strategy;

public interface Strategy {
    void algorithmInterface();
}

class StrategyA implements Strategy{

    public void algorithmInterface() {
        System.out.println("级别一处理逻辑");
    }
}

class StrategyB implements Strategy{

    public void algorithmInterface() {
        System.out.println("级别二处理逻辑");
    }
}

class StrategyC implements Strategy{

    public void algorithmInterface() {
        System.out.println("级别三处理逻辑");
    }
}

class Context{
    private Strategy strategy;
    Context(Strategy strategy) {
        this.strategy = strategy;
    }

    void algorithmInterface() {
        strategy.algorithmInterface();
    }
}

class Client {
    public static void main(String[] args) {
        Strategy strategyA = new StrategyA();
        Context context = new Context(strategyA);
        context.algorithmInterface();
        context = new Context(new StrategyB());
        context.algorithmInterface();
        context = new Context(new StrategyC());
        context.algorithmInterface();
    }
}
向AI问一下细节

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

AI