学习设计模式——创建型模式day01

单例模式:

1.饿汉式加载

简单的来说就是构造器私有并且一上来就先把对象new出来
典型的问题就是浪费空间

public class Hungry {
    private Hungry(){
    }

    private final static  Hungry hungry =new Hungry();

    public static Hungry getInstance(){
        return hungry;
    }

}

2.懒汉模式:

原始版本
简单的来说就是要用的时候再加载、
最大的问题就是存在线程安全问题

public class LazyMan {
    private LazyMan(){
        
    }
    
    private static LazyMan lazyMan;
    
    public static LazyMan getInstance(){
        if(lazyMan==null){
            lazyMan=new LazyMan();
        }
        return lazyMan;
    }
}

双重检测锁模式(DCL懒汉式):
要注意:这个lazyMan = new LazyMan();不是原子性操作,可能发生指令重排,
所以必须加上volatile

public class LazyMan {
    private LazyMan(){
    }
    private static volatile LazyMan lazyMan;

    public static LazyMan getInstance(){
        if(lazyMan==null) {
            synchronized (LazyMan.class) {
                if (lazyMan == null) {
                    lazyMan = new LazyMan();
                }
            }
        }
        return lazyMan;
    }
}
3.静态内部类
public class Holder {
    private Holder(){

    }

    private static Holder getInstance(){
        return InnerClass.holder;
    }

    public static class InnerClass{
        private static final Holder holder =new Holder();
    }
}

问题:归根结底也是不安全的,反射太牛逼,破坏一切
反射大法
反射可以破坏单例模式,举个栗子

public class LazyMan {
    private LazyMan(){
    }
    private static LazyMan lazyMan;

    public static LazyMan getInstance(){
        if(lazyMan==null) {
            synchronized (LazyMan.class) {
                if (lazyMan == null) {
                    lazyMan = new LazyMan();
                }
            }
        }
        return lazyMan;
    }

    public static void main(String[] args) throws Exception {
        LazyMan instance =LazyMan.getInstance();
        Constructor<LazyMan> de =LazyMan.class.getDeclaredConstructor(null);
        de.setAccessible(true);

        LazyMan instance2=de.newInstance();

        System.out.println(instance);
        System.out.println(instance2);
    }
}

结果:单例模式被破坏
在这里插入图片描述

最后的结论是道高一尺魔高一丈。怎么优化也顶不住反射

最后,我们说一下枚举,枚举很特殊,它在类加载的时候会初始化里面的所有的实例,而且 JVM 保证了它们不会再被实例化,所以它天生就是单例的。
虽然我们平时很少看到用枚举来实现单例,但是在 RxJava 的源码中,有很多地方都用了枚举来实现单例。

工厂模式

工厂模式主要用到的原则:
开闭原则:一个软件的实体应当对扩展开放,对修改关闭
依赖倒转原则:要针对接口编程,不要针对实现编程
迪米特法则:只与直接朋友通信,而避免和陌生人通信

工厂模式的核心:
实例化对象不使用new,用工厂方法代替
将选择实现类,创海对象统一管理和控制,从而将调用者跟我们的实现类解耦

三种模式:
简单工厂模式(又叫做静态工厂模式):
用来生产统一等级结构的任意产品(对于增加新的产品,需要覆盖已有的代码)
虽然某种程度上不符合设计原则,但实际使用较多

简单地说,简单工厂模式通常就是这样,一个工厂类
XxxFactory,里面有一个静态方法,根据我们不同的参数,返回不同的派生自同一个父类(或实现同一接口)的实例对象。我们客户取产品只需要告诉工厂需要产品的名字,不用管实现

要增加一个产品是需要修改代码的,但是由于该模式比较简单,仍然被大量使用

工厂方法模式:
用来生产统一等级结构的固定产品(支持增加任意产品)
不修改已有类的前提下,通过增加新的工厂类实现扩展
其实就是每一种产品对应一个工厂,这会便于横向扩展

抽象工厂模式:
围绕一个超级工厂创造其他工厂。该超级工厂又称为其他工厂的工厂。
一个工厂生产的是一个产品系列。

优点:

  • 具体产品在应用层的代码隔离,无需关心创建细节。
  • 将一个系列的产品统一到一起创建

缺点:

  • 规定了所用可能被创建的产品集合,产品簇中扩展新的产品困难
  • 增加了系统的抽象性和理解难度

举个栗子

//手机产品接口
public interface IphoneProduct {
    void start();
    void shutdown();
    void callup();
    void sendSMS();
}
//路由器产品接口
public interface IRouteProduct {
    void start();
    void shutdown();
    void openwifi();
    void setting();
}

//使用到了以上定义的两种工厂,但是工厂生产什么不需要关心
public interface IProductFactory {
    IphoneProduct iphoneProduct();

    IRouteProduct routerProduct();
}

实现具体的设计

//小米生产手机
public class XiaomiPhone implements IphoneProduct{
    public void start() {
        System.out.println("开启小米手机");
    }

    public void shutdown() {
        System.out.println("关闭小米手机");
    }

    public void callup() {
        System.out.println("小米手机打电话");
    }

    public void sendSMS() {
        System.out.println("小米手机发短信");
    }
}

//小米生产路由器
public class XioamiRouter implements IRouteProduct {
    public void start() {
        System.out.println("开启小米路由器");
    }

    public void shutdown() {
        System.out.println("关闭小米路由器");
    }

    public void openwifi() {
        System.out.println("小米路由器打开wifi");
    }

    public void setting() {
        System.out.println("小米路由器设置密码");
    }
}


//小米工厂,实现了产品工厂类(而产品工厂类的规范又来自于路由器和手机的抽象类)
public class XiaomiFactory implements IProductFactory {
    public IphoneProduct iphoneProduct() {
        return new XiaomiPhone();
    }

    public IRouteProduct routerProduct() {
        return new XioamiRouter();
    }
}

实现:

public class Clinet {
    public static void main(String[] args) {
        System.out.println("===============小米系列产品========================");

        XiaomiFactory  xiaomiFactory=new XiaomiFactory();
        IphoneProduct iphoneProduct=xiaomiFactory.iphoneProduct();
        iphoneProduct.callup();
        iphoneProduct.sendSMS();

        IRouteProduct iRouteProduct= xiaomiFactory.routerProduct();
        iRouteProduct.openwifi();

    }
}

结果:
在这里插入图片描述
难扩展性:比如要生产一个键盘,那么所有工厂都加上制造键盘的方法。这显然违反了对修改关闭对扩展打开的原则

再谈一下适用条件:
当涉及到产品族(它代表了组成某个产品的一系列附件的集合)的时候,就需要引入抽象工厂模式了。当涉及到这种产品族的问题的时候,就需要抽象工厂模式来支持了。我们不再定义
CPU 工厂、主板工厂、硬盘工厂、显示屏工厂等等,我们直接定义电脑工厂,每个电脑工厂负责生产所有的设备,这样能保证肯定不存在兼容问题。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值