常用设计模式(单例、工厂、适配器)

1、单例模式 (√)

        单例模式是Java设计模式中最简单的设计模式之一,是属于创建型设计模式。所谓的单例模式,目的就是使设计单例模式的类,只会创建一个对象,并且这个对象也会提供一个全局访问的方法,进行访问。

单例模式的特点:

  • 单例类只能有一个实例。

  • 单例类的对象只能由自己创建自己的唯一对象。

  • 单例类必须要给其他所有的类提供这一个唯一的对象。

  • 单例类中的构造函数必须是私有的,就是为了防止出现多次创建。

单例模式的具体实现有以下几种方式:
    1、饿汉式(单例实现)
/**
 * 饿汉式单例实现
 */
public class SimpleObjectMyApplication {

    // 构造私有
    private SimpleObjectMyApplication() {}
    // 上来就创建实例
    private static SimpleObjectMyApplication instance = new SimpleObjectMyApplication();
    // 设置一个公共的方法,用于访问这个变量
    public static SimpleObjectMyApplication getInstance() {
        return instance;
    }
}

特点:

  • 线程安全:是线程安全的,因为他一上来就去创建实例,并且这个实例用static关键字修饰,在类加载的时候就已经初始化好了,并且只会初始化一次。

  • 不能创建对象,构造函数私有化,就只能通过静态的函数进行调用公共方法。那在静态方法中就只能调用静态的成员,不能调用非静态成员,所以刚好在这种情况下,自身形成了线程安全。

    2、懒汉式(单例实现)
/**
 * 懒汉式单例实现(懒汉式是属于调用的时候才去创建实例)
 */
public class SimpleObjectMyApplication {

    // 构造私有
    private SimpleObjectMyApplication() {}
    // 声明变量
    private static SimpleObjectMyApplication instance;
    // 设置一个公共的方法,用于访问这个变量
    public static SimpleObjectMyApplication getInstance() {
        if (instance == null) {
            return new SimpleObjectMyApplication();
        }
        return instance;
    }
}
从上面的代码可以发现:为了实现只创建一个单例对象,就使用:
if (instance == null) {
    return new SimpleObjectMyApplication();
}
if语句判断当前的对象实例是不是为空,若为空就创建一个,不为空就返回已经创建好了的。但是这样会发生一个问题,在多线程中调用单例类,会出现线程不安全。所以代码修改如下:
/**
 * 懒汉式单例实现(懒汉式是属于调用的时候才去创建实例)
 */
public class SimpleObjectMyApplication {

    // 构造私有
    private SimpleObjectMyApplication() {}
    // 声明变量
    private static SimpleObjectMyApplication instance;
    // 设置一个公共的方法,用于访问这个变量
    // 添加 synchronized 关键字
    public static synchronized SimpleObjectMyApplication getInstance() {
        if (instance == null) {
            return new SimpleObjectMyApplication();
        }
        return instance;
    }
}
    3、双重检测机制 (线程安全,在多线程环境下,性能还是不错的)
/**
 * 双重检测单例实现(懒汉式是属于调用的时候才去创建实例)
 */
public class SimpleObjectMyApplication {

    // 构造私有
    private SimpleObjectMyApplication() {}
    // 声明变量
    private static SimpleObjectMyApplication instance;
    // 设置一个公共的方法,用于访问这个变量
    public static synchronized SimpleObjectMyApplication getInstance() {
        if (instance == null) {
            synchronized (SimpleObjectMyApplication.class) {
                if (instance == null) {
                    instance = new SimpleObjectMyApplication();
                }
            }
        }
        return instance;
    }
}
4、静态内部类

这种方式同样利用了 classloader 机制来保证初始化 instance 时只有一个线程,它跟第 1 种方式不同的是:
第 1 种方式只要 Singleton 类被装载了,那么 instance 就会被实例化(没有达到 lazy loading 效果),而这种方式是 Singleton 类被装载了,instance 不一定被初始化。
因为 SingletonHolder 类没有被主动使用,只有通过显式调用 getInstance 方法时,才会显式装载 SingletonHolder 类,从而实例化 instance。
/**
 * 静态内部类
 */
public class SimpleObjectMyApplication {

    // 构造私有
    private SimpleObjectMyApplication() {}

    private static class SimpleObjectInner {
        private static final SimpleObjectMyApplication instance = new SimpleObjectMyApplication();
    }

    public static final SimpleObjectMyApplication getInstance() {
        return SimpleObjectInner.instance;
    }

}
5、枚举
    这种实现方式还没有被广泛采用,但这是实现单例模式的最佳方法。它更简洁,自动支持序列化机制,绝对防止多次实例化。
这种方式是 Effective Java 作者 Josh Bloch 提倡的方式,它不仅能避免多线程同步问题,而且还自动支持序列化机制,防止反序列化重新创建新的对象,绝对防止多次实例化。不过,由于 JDK1.5 之后才加入 enum 特性,用这种方式写不免让人感觉生疏,在实际工作中,也很少用。
不能通过 reflection attack 来调用私有构造方法。
public enum SimpleObjectApplication {
    INSTACE;
    public void function() {
        
    }
}
总的来说:
1、饿汉式是线程安全、调用效率高、但是不支持延时加载。
2、懒汉式是线程不安全、调用效率也不高,但是支持延时加载。
3、静态内部类是线程安全、调用效率高,并且还支持延时加载。

2、工厂模式 (√)
        工厂模式的实现主要是为了使创建者与调用者进行分离。如果不使用工厂模式创建对象和调用对象的话,就会出现,调用者需要知道很多的额创建者的信息,整体的结构复杂,代码的耦合度也是很高的。
        工厂模式包括三种实现:
            1、简单工厂模式
            2、工厂模式
            3、抽象工厂模式
        
        首先,了解简单工厂模式:
            简单工厂模式又叫做:静态工厂模式。它是通过在创建类中实现添加静态方法,每一个静态方法都对应一个具体的创建者,进行创建并返回,调用者只需要在调用中通过该类的静态方法实现创建实体类。
            但是,也有一个缺点就是:不能做到对扩展开放,对修改关闭,必须是在扩展的时候,是要修改代码的。

            不使用工厂模式的示例:
public interface Car {
    void run();
}
public class BYD implements Car{
    @Override
    public void run() {
        System.out.println("比亚迪在跑步");
    }
}
public class WL implements Car{
    @Override
    public void run() {
        System.out.println("五菱在飙车");
    }
}
public class Main {
    public static void main(String[] args) {
        Car car1 = new BYD();
        Car car2 = new WL();
        car1.run();
        car2.run();
    }
}
            关系图如下:
        
            使用简单工厂模式,示例如下:

public interface Car {
    void run();
}
public class BYD implements Car{
    @Override
    public void run() {
        System.out.println("比亚迪在跑步");
    }
}
public class WL implements Car{
    @Override
    public void run() {
        System.out.println("五菱在飙车");
    }
}
public class SimpleFactory {
    public static WL createWL() {
        return new WL();
    }

    public static BYD createBYD() {
        return new BYD();
    }
}
public class Main {
    public static void main(String[] args) {
        Car car1 = SimpleFactory.createWL();
        Car car2 = SimpleFactory.createBYD();
        car1.run();
        car2.run();
    }
}
            关系图如下:
        

        结构虽然看起来比之前的复杂了,但是对于调用者来说,就很轻松,不管以后的结构多复杂,调用者只需要知道Car接口和SimpleFactory简单工厂类。

        工厂方法模式工厂方法模式的出现是为了解决简单工厂模式不能对修改关闭,修改的时候必须要修改源代码,否则无法实现扩展。
        工厂模式之所以能实现对扩展开放,对修改关闭,是因为,他会对每一个类都创建一个工厂,该工厂只会为该类使用,每个类的创建是不会相互影响的,但是这样也就会造成一个缺点:就是创建的类很多。
        具体事例如下:
public interface Car {
    void run();
}
public interface CarFactory {
    Car createCar();
}
public class BYD implements Car {
    @Override
    public void run() {
        System.out.println("比亚迪在跑步");
    }
}
public class BYDFactory implements CarFactory {

    @Override
    public Car createCar() {
        return new BYD();
    }
}
public class WL implements Car {
    @Override
    public void run() {
        System.out.println("五菱在飙车");
    }
}
public class WLFactory implements CarFactory {

    @Override
    public Car createCar() {
        return new WL();
    }
}
public class Main {
    public static void main(String[] args) {
        Car c1 = new BYDFactory().createCar();
        Car c2 = new WLFactory().createCar();
        c1.run();
        c2.run();
    }
}
        整个的代码结构:
        

        后期想要实现扩展,就很简单了,只需要创建一个实体类,该实体类实现Car接口方法,再创建一个对应的工厂方法,使之能够去创建该实体类。
        结构关系图:
        

            简单工厂模式与工厂模式的区别:
            1、从代码和功能的扩展上来看,都能扩展功能,但是简单工厂是需要修改源代码的,不支持开闭原则,但是工厂模式是支持开闭原则的。
            2、从结构的复杂度上看,简单工厂模式的结构比较简单,而工厂模式涉及的类很多,之所以能实现开闭原则,就是去创建更多的类实现。
            3、从使用上来看,使用的最多的还是简单工厂模式,涉及的类少,结构不复杂,但是从设计原理来看,是需要使用工厂模式的。

            抽象工厂模式
            抽象工厂是工厂模式的升级版本,不管是简单工厂模式还是工厂模式,都是生产某一个产品,但是呢,现在抽象工厂模式可以生产一个产品族,比如合一生产一套高端的物件,可以生产一套低端的产品,抽象工厂不能生成一个产品。
            具体事例如下:
public interface Seat {
    void massage();
}

class LuxurySeat implements Seat {

    @Override
    public void massage() {
        System.out.println("高端座椅--可以按摩");
    }
}

class LowSeat implements Seat {

    @Override
    public void massage() {
        System.out.println("低端座椅--不能按摩");
    }
}
public interface Engine {
    void run();
    void start();
}

class LuxuryEngine implements Engine {

    @Override
    public void run() {
        System.out.println("高端引擎--跑的块");
    }

    @Override
    public void start() {
        System.out.println("高端引擎--启动的块");
    }
}

class LowEngine implements Engine {

    @Override
    public void run() {
        System.out.println("低端引擎--跑的慢");
    }

    @Override
    public void start() {
        System.out.println("低端引擎--启动的慢");
    }
}
public interface CarFactory {

    Engine createEngine();
    Seat createSeat();

}
public class LowFactory implements CarFactory{
    @Override
    public Engine createEngine() {
        return new LowEngine();
    }

    @Override
    public Seat createSeat() {
        return new LowSeat();
    }
}
public class LuxuryFactory implements CarFactory{
    @Override
    public Engine createEngine() {
        return new LuxuryEngine();
    }

    @Override
    public Seat createSeat() {
        return new LuxurySeat();
    }
}
public class Client {
    public static void main(String[] args) {

        CarFactory carFactory = new LuxuryFactory();
        Engine engine = carFactory.createEngine();
        engine.run();
        engine.start();

        CarFactory carFactory1 = new LowFactory();
        Seat seat = carFactory1.createSeat();
        seat.massage();

    }
}
        具体结果:
        
        
            工厂模式的总结
            1、简单工厂模式,也叫静态工厂模式
                虽然某种程度上不符合设计原则,但是实际是用最多。
            2、工厂方法模式
                不修改已有类的前提下,通过添加新的工厂类来实现开闭原则,进行扩展。
            3、抽象工厂模式
                不可以增加产品,但是可以增加产品族!

3、适配器模式 (√)

    什么是适配器模式?适配器模式就是将一个类的接口转换成客户希望的另一个接口。Adapter模式使得原本由于接口不兼容,而不能进行正常工作的,适配后能够正常工作。
    在适配器模式中,包含三种角色:
    第一、目标接口(Target):客户所期待的适配之后的接口。
    第二、需要被适配的类(Adaptee):需要适配的类。
    第三、适配器(Adapter):可以通过包装一个被适配的对象,将原接口转换成被适配的接口。
    具体示例如下:
/**
 * 需要被适配的类
 */
public class Adaptee {
    public void run() {
        System.out.println("被适配的类运行");
    }
}
/**
 * 桥梁接口
 */
public interface Target {
    void TargetRun();
}
/**
 * 桥梁实现类
 */
public class Adapter extends Adaptee implements Target {
    //这个桥梁需要把被适配的类,组合进来形成组合关系,才能进行适配
    @Override
    public void TargetRun() {
        super.run();
    }
}
/**
 * 客户端类
 * 客户端是通过适配器来进行与被适配的类实现联系的
 */
public class Client {
    // 想要实现在客户端和被支配的类进行联系,首先把适配器的接口,组合进来
    // 再加上适配器接口,又组合了被适配的类,所以,可以达到适配目的
    public void TargetClient(Target target) {
        target.TargetRun();
    }
    public static void main(String[] args) {
        Client client = new Client();
        Adaptee adaptee = new Adaptee();
        Target target = new Adapter();
        client.TargetClient(target);
    }
}





















        
全部评论

相关推荐

10-13 17:47
门头沟学院 Java
wulala.god:图一那个善我面过,老板网上找的题库面的
点赞 评论 收藏
分享
10-30 23:23
已编辑
中山大学 Web前端
去B座二楼砸水泥地:这无论是个人素质还是专业素质都👇拉满了吧
点赞 评论 收藏
分享
评论
点赞
收藏
分享
牛客网
牛客企业服务