详解常用的设计模式——单例模式、工厂模式、代理模式

设计模式遵循的原则有6个

  • 开闭原则(Open Close Principle) 对扩展开放,对修改关闭。
  • 里氏代换原则(Liskov Substitution Principle) 只有当衍生类可以替换掉基类,软件单位的功能不受到影响时,基类才能真 正被复用,而衍生类也能够在基类的基础上增加新的行为。
  • 依赖倒转原则(Dependence Inversion Principle) 这个是开闭原则的基础,对接口编程,依赖于抽象而不依赖于具体。
  • 接口隔离原则(Interface Segregation Principle) 使用多个隔离的借口来降低耦合度。
  • 迪米特法则(最少知道原则)(Demeter Principle) 一个实体应当尽量少的与其他实体之间发生相互作用,使得系统功能模块相 对独立。
  • 合成复用原则(Composite Reuse Principle) 原则是尽量使用合成/聚合的方式,而不是使用继承。继承实际上破坏了类 的封装性,超类的方法可能会被子类修改。

单例模式

定义:确保某一个类只有一个实例,而且自行实例化并向整个系统提供这个实例。

  • 构造方法必须是私有的,防止被外部实例
  • 一个类只有一个实例,属于这个类,所以这个实例应该是这个类的成员变量,静态变量

懒汉式

在第一次使用的时候进行类加载。

/**
 * 懒汉式单例模式(双重校验的、线程安全的)
 *
 * @Author guoXin Sun
 * @Date 2022/3/9 15:14
 * @Version 1.0
 */
public class LazySingleton {


    //持有私有静态实例,防止被引用,此处赋值为null,目的是实现延迟加载
    private static LazySingleton instance = null;

    /* 私有构造方法,防止被实例化 */
    private LazySingleton() {
    }

    /* 1:懒汉式,静态工程方法,创建实例 */
    public static LazySingleton getInstance() {
        if (instance == null) {
            //线程安全
            synchronized (LazySingleton.class) {
                if (instance == null) {
                    instance = new LazySingleton();
                }
            }
        }
        return instance;
    }
}

饿汉式

在类加载的时候就进行实例化

使用场景

  • 要求生成唯一序列号的环境;
  • 在整个项目中需要一个共享访问点或共享数据,例如一个Web页面上的计数器,可以不用把每次刷新都记录到数据库中,使用单例模式保持计数器的值,并确保是线程安全的;
  • 创建一个对象需要消耗的资源过多,如要访问IO和数据库等资源;
  • 需要定义大量的静态常量和静态方法(如工具类)的环境,可以采用单例模式 (当然,也可以直接声明为static的方式)。
/**
 * 饿汉式单例
 * @Author guoXin Sun
 * @Date 2022/3/9 15:14
 * @Version 1.0
 */
public class HurrySingleton {

    private volatile static HurrySingleton instance = new HurrySingleton();

    /* 私有构造方法,防止被实例化 */
    private HurrySingleton() {
    }

    // 创建实例,并返回
    public static HurrySingleton getInstance() {
        return instance;
    }
}

代理模式

为其他对象提供一种代理以控制对这个对象的访问

使用场景:网络连接的建立、IO流的建立、日志

请添加图片描述

public class Proxy {
    public static void main(String[] args) {
        SubjectProxy subjectProxy = new SubjectProxy(new RealSubject());
        subjectProxy.doSome();
    }
}

interface Subject {
    void doSome();
}

/**
 * 目标类
 */
class RealSubject implements Subject {

    @Override
    public void doSome() {
    }
}

/**
 * 静态代理类
 */
class SubjectProxy implements Subject {

    private RealSubject subject;

    public SubjectProxy(RealSubject subject) {
        this.subject = subject;
    }

    @Override
    public void doSome() {
        System.out.println("执行前");
        System.out.println("执行中");
        System.out.println("执行后");
    }
}

工厂模式

  • 我们最常用的 Spring 就是一个最大的 Bean 工厂,IOC 通过FactoryBean对Bean 进行管理。
  • 我们使用的日志门面框架slf4j,点进去就可以看到熟悉的味道

简单工厂模式

简单工厂模式,它属于类创建型模式,在简单工厂模式中,可以根据参数的不同返回不同类的实例

专门定义一个类来负责创建其他类的实例,被创建的实例通常都具有共同的父类。

三个角色:工厂类、抽象类产品、具体产品

优点:将对象的创建和使用彻底分离

缺点:不够灵活,如果新增产品就需要修改工厂类源码

请添加图片描述

/**
 * 简单工厂模式
 * @Author guoXin Sun
 * @Date 2022/3/9 17:37
 * @Version 1.0
 */
public class SimpleFactory {

    public static Product createProduct(String type) {
        if ("A".equals(type)) {
            return new ProductA();
        }
        return new ProductB();
    }

    public static void main(String[] args) {
        Product a = createProduct("B");
        a.print();
    }
}

/**
 * 共同父类抽象类
 */
abstract class Product {
public abstract void print();
}

/**
 * 产品A
 */
class ProductA extends Product {

    @Override
    public void print() {
        System.out.println("产品A被创建");
    }
}

/**
 * 产品B
 */
class ProductB extends Product {

    @Override
    public void print() {
        System.out.println("产品B被创建");
    }
}

工厂方法模式

定义一个用于创建对象的接口,让子类决定实例化哪个类。工厂方法使一个类的实例化延迟到其子类

生产哪个对象不再由参数决定,而是创建工厂时,调用工厂的方法创建。

四个角色:产品抽象类、产品类、工厂接口、工厂实现类

完全符合开闭原则

使用:数据库访问、记录日志

优点:扩展性高

缺点:每次增加产品都需要新建工厂类和实现的工厂。

请添加图片描述

/**
 * 工厂模式
 * @Author guoXin Sun
 * @Date 2022/3/9 18:11
 * @Version 1.0
 */
public class Factory {
    public static void main(String[] args) {
        FactoryA factoryA = new FactoryA();
        factoryA.createFactory().print();
    }
}

/**
 * 抽象的工厂接口
 */
interface AbstractFactory{
     Fruit createFactory();
}

class FactoryA implements AbstractFactory {
    @Override
    public Fruit createFactory() {
        return new Apple();
    }
}
class FactoryB implements AbstractFactory {
    @Override
    public Fruit createFactory() {
        return new Orange();
    }
}


/**
 * 抽象产品
 */
abstract class Fruit {
    public abstract void print();
}

/**
 * 产品A
 */
class Apple extends Fruit {
    @Override
    public void print() {
        System.out.println("生产一个苹果");
    }
}

/**
 * 产品B
 */
class Orange extends Fruit {
    @Override
    public void print() {
        System.out.println("生产一个橘子");
    }
}

抽象工厂模式

因为工厂方法模式中的每个工厂只生产一类产品,可能会导致系统中存在大量的工厂类,势必会增加系统的开销。所以我们可以考虑将一些相关的产品组成一个“产品族”,由同一个工厂来统一生产

产品族是指位于不同产品等级结构中功能相关联的产品组成的家族

定义:为创建一组相关或相互依赖的对象提供一个接口,而且无须指 定它们的具体类。

五个角色:抽象工厂、具体工厂、抽象产品、具体产品

请添加图片描述

/**
 * @Author guoXin Sun
 * @Date 2022/3/9 20:16
 * @Version 1.0
 */
public class AbstractFactory {
    public static void main(String[] args) {
        Shape shape = new FactoryRedShape1().getShape();
        shape.print();

        Shape shape1 = new FactoryBlueShape1().getShape();
        shape1.print();
    }
}

/**
 * 抽象产品接口
 */
interface Shape {
    void print();
}

/**
 * 抽象实现接口
 */
abstract class Shape1 implements Shape {
    public abstract void print();
}

abstract class Shape2 implements Shape {
    public abstract void print();
}

/**
 * 具体实现类
 */
class RedShape1 extends Shape1{

    @Override
    public void print() {
        System.out.println("红色的形状1");
    }
}

class BlueShape1 extends Shape2{
    @Override
    public void print() {
        System.out.println("蓝色的形状2");
    }
}


/**
 * 抽象工厂
 */
interface ShapeFactory {
    Shape getShape();

}
/**
 * 具体工厂
 */
class FactoryRedShape1 implements ShapeFactory {
    @Override
    public Shape getShape() {
        return new RedShape1();
    }

}

class FactoryBlueShape1 implements ShapeFactory {
    @Override
    public Shape getShape() {
        return new BlueShape1();
    }

}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值