大话设计模式(更新ing...)

目录

单例模式:

简单工厂模式

工厂方法模式

抽象工厂模式

策略模式

观察者模式

适配器模式

模板方法模式(模板模式)

装饰者模式

静态代理模式

动态代理模式

责任链模式

享元模式

迭代器模式

桥接模式


单例模式:

方式一:拿去吧!

如果一个对象被new了多次,但无法保证每个对象都会被使用,这时候就会很浪费空间,而且如果访问量巨大,服务器也要承担很大的压力。出现这种情况,一些Java大神们当然不会放任着不管,于是经过一番潜心研究,就出现了一种新的获得对象的方式——单例模式。

单例模式大概做的事情就是通过自己的设计,让当前的这个类只能产生一个对象(但是根据特定情况以及自己对于这一块的设计,不能一刀切的都去用这个方法,比如一个person类,每个person都有自己不同的属性,怎么能都用一个person来做事情呢)。

如果做?

  1. 保证当前类的构造方法不能被随便调用吧,这是最基本的条件。也就是让构造方法私有化--private XXX(){}
  2. 不能调用构造方法,那我怎么获取这个对象呢。有四种方式: 
    1. 构造方法
    2. 代码块
    3. 普通方法
    4. 属性

构造方法:前面我们为了不能随便创建当前对象,已经给构造方法私有化,所以排除此方法。

代码块:代码块会在对象创建的时候就加载了,但是没有返回值,同样获取不到对象,排除。

普通方法:这个似乎和构造方法一样了,每次调用这个方法同样会创建一个对象出来,也无法做到对象时单例的。

属性: 似乎只能使用属性来new对象,然后通过方法来将对象传递。

                public Singleton single = new Singleton();

上面这个写法很明显是不对的,而且在做单例上面,似乎没有任何存在的意义。

原因是啥呢?

首先,这样写上来就是一个StackOverflow Error。因为这是类里面的属性,类加载以后会加载自己里面的属性,方法等。但是当加载这个属性的时候,发现又new了一个自己,然后又去加载自己类,又遇到一个属性里面new了一个自己。。。陷入死循环导致栈溢出。

解决方法:保证是一份就OK啦。 public static Singleton single = new Singleton();

有些朋友可能看出还有一个问题:就是这样写我岂不是用类名就可以随便调用了,Singleton.single简直不要太简单。所以呢,为了让我的获取对象的方法更有存在感,必然是不能让您调用的嗷。

较为标准的写法:private static Singleton single = new Singleton();

好啦。属性对象创建好了,我怎么给你呢--->通过方法获得。 设计一个方法,将当前唯一的对象返回出去。       

public static Singleton getInstance(){

     //注意:这里return的是single属性中存储对象的地址引用

     return single;

}

这种方式又叫做饿汉式,也就是:上来就创建一个对象,如同饿汉见到食物上来就吃。但是呢,这样在整个系统执行过程中,如果创建的对象不使用,就会一直占用着内存,造成了内存空间的浪费。


方式二:不用,我就不做!

这种方式呢,又叫做懒汉式,就是你可以要,但是我未必会创建,等到你用的时候我再创建,这样就很大程度上避免了内存空间浪费问题。写法和饿汉式几乎一致,代码如下:

private Singleton(){}
//我先不创建对象
private static Singleton single;
public static Singleton getInstance(){
    //这个时候你要用了,但是我要看看是否真的没有创建好的对象吗,没有我再给你
    if(single == null){
        single = new Singleton();
    }
    return single;
}

有利肯定有弊:这时候要考虑到线程的问题了,比如A和B两个线程,同时需要这个对象,假如A先开辟了一块空间single,A正准备判断对象是否为空,这个时候时间片轮转,到B了,B也开辟了一块空间,然后A又创建了对象,但此时B判断对象已经不为空了,但是自己又开辟了一块空间,就比较冲突。当线程数更多的话,资源的争夺就会更明显。所以,请看下个分解。


方式三:我给锁住,让你抢我的东西!

在懒汉式的基础上加一个锁,就是我在用这个对象的时候,我要给他锁住,你们谁也不能动,直到我用完。代码实现如下:

private Singelton(){}
private static Singleton single;
//当前线程使用的时候不允许其他线程操作
public synchronized static Singleton getInstance(){
    if(single == null){
        single = new Singleton();
    }
    return single;
}

有利有弊:这种整个方法的执行过程中,不能有其他线程操作的方式,线程安全是解决了,万一你用很久,谁等的起啊。


方式四:双重判定!

就是将当前的类模板锁住,而不是锁住整个对象,这样其他线程进来如果对象不是空的,就可以直接返回了,而不需要去等待加锁的线程执行完毕,这样大大提高了执行效率。实现如下:

private Singelton(){}
private static Singleton single;
public static Singleton getInstance(){
    //第一重判定,如果为空,加锁,创建对象
    if(single == null){
        synchronized(Singleton.class){
            //第二重判定,如果为空 创建对象
            if(single == null){
                single = new Singleton();
            }
        }
    }
    return single;
}

有利有弊:这样在解决了加锁性能的问题的同时,在JVM虚拟机中,在对象的开辟和赋值的过程中,可能会产生指令重排序。本来时1 ——> 2 ——> 3的顺序,可能会变成 1 ——> 3 ——> 2。

  1. 为 instance分配内存空间。
  2. 初始化 instance
  3. 将 instance指向分配的内存地址。

方式五:大哥来了!

属性上添加volatile,保证属性在加载和赋值的过程中,不会被JVM指令重排序。代码如下:

private Singleton single(){}
private static volatile Singleton single;
public static Singleton getInstance(){
    if(single == null){
        synchronized(Singleton.class){
            if(single == null){
                single = new Singleton();
            }
        }

    }
}

简单工厂模式

大家所熟知的有工厂方法模式、抽象工厂模式,那么简单工厂模式又是什么呢?简单工厂模式不能算作一个标准的设计模式,但是呢,在开发之中又挺常用的,那么就当做一个热身吧!

举一个小案例:话说有一天晚上,博主突发饿疾,非要去附近的小作坊买一些关东煮吃吃。且附近几家都有卖。那么问题来了,我新来的这个地方,还不熟悉,我还没吃过这附近的关东煮呢,万一关东煮里面有其他东西,出了问题,我找谁去呢??找我买东西的那家店?万一人家无证经营跑路了呢。所以为了安全起见,我需要看到人家的营业执照才放心的买。那么这就要求这些小作坊需要被统一管理起来(颁发营业执照,你这家店可以卖关东煮),或者说的贴切代码一些(遵循一个规则)。

好,假设有三家小作坊店,为了方便理解,类名就用拼音了(其实是我不会英语)。那么:GuanDongZhu1.java    GuanDongZhu2.java    GuanDongZhu3.java。这是我附近的三家店。现在我要给他们指定一个规则,允许他们卖关东煮。AcceptGuanDongZhu.java。既然是指定规则的类,我们就可以将它指定为借口或者父类。此例中将其指定为借口。那么三个小作坊店都实现这个借口里面的方法(卖关东煮)。代码如下:

GuanDongZhu1.java

public class GuanDongZhu1 implements AcceptGuanDongZhu{
    @Override
    public void sale() {
        System.out.println("GuanDongZhu1号店也售卖关东煮,博主快来吃啊");
    }
}

GuanDongZhu2.java

public class GuanDongZhu2 implements AcceptGuanDongZhu{
    @Override
    public void sale() {
        System.out.println("GuanDongZhu2号店售卖关东煮,博主快来吃啊");
    }
}

GuanDongZhu3.java

public class GuanDongZhu3 implements AcceptGuanDongZhu{
    @Override
    public void sale() {
        System.out.println("GuanDongZhu3号店关东煮最好吃,博主快来吃啊");
    }
}

AcceptGuanDongZhu.java

public interface AcceptGuanDongZhu {
    //售卖关东煮的接口方法(营业执照)  默认用 public abstract修饰
    void sale();
}

TestMain.java

public static void main(String[] args) {
        //多态来创建子类对象
        AcceptGuanDongZhu sale = new GuanDongZhu1();
        sale.sale();
}

好,营业执照给了,小作坊也遵循了,但是!新的问题来了。用户这样用,是不是知道的太多了。首先,他知道了我的接口规则(实现了AcceptGuanDongZhu这个接口),其次,我具体的实现类也让他知道了,这完全违背封装隔离的思想啊。那么我就需要把用户和店隔开,用户可以看见我的实现规则,但是呢,我不能让你知道我的具体实现类是哪个,你可以通过传参数的方式,告知我想去哪个店,我给你找。而中间这个隔离层呢,就是我们今天的重点了——Factory。就是你告诉我工厂,你要买关东煮了,如果你传给我一个参数(店名),那我就把这个店给到你,不传,我就随便给你一个。按照这种封装隔离的思想,把具体的实现类包装起来。代码实现如下:

GuanDongZhuFactory.java

//调用我工厂 我要给你返回一个店  你给我传一个店名 或者不传我就随机给你一个
    public AcceptGuanDongZhu getGuanDongZhu(String name){
        //下面就简单做个判断,重要的是思想
        if(!"".equals(name) && "GuanDongZhu1".equals(name)){
            return new GuanDongZhu1();
        }else if(!"".equals(name) && "GuanDongZhu2".equals(name)){
            return new GuanDongZhu2();
        }else if(!"".equals(name) && "GuanDongZhu3".equals(name)){
            return new GuanDongZhu3();
        }else{
            //啥也不传,我给你选一个
            return new GuanDongZhu1();
        }
    }

那么这时候用户找店的方式就应该变成:

TestMain.java

public static void main(String[] args) {
        //先创建工厂
        GuanDongZhuFactory factory = new GuanDongZhuFactory();
        AcceptGuanDongZhu sale = factory.getGuanDongZhu("GuanDongZhu1");
        sale.sale();
    }

工厂方法模式

引子:为什么会有工厂方法模式?

在上面的简单工厂模式中,用户通过创建工厂对象来获取目标对象(GuanDongZhu对象),那么由于关东煮不止一家,用户肯定有自己想去的一家,在简单工厂模式中依靠传参数来决定选择哪一家,那这就意味着用户需要了解参数的意义。而且啊,添加了参数,我工厂处理的时候岂不是多了很多的判断,如:下面就是简单工厂中的工厂要做的事情。

if(!"".equals(name) && "GuanDongZhu1".equals(name)){
            return new GuanDongZhu1();
        }else if(!"".equals(name) && "GuanDongZhu2".equals(name)){
            return new GuanDongZhu2();
        }else if(!"".equals(name) && "GuanDongZhu3".equals(name)){
            return new GuanDongZhu3();
        }else{
            //啥也不传,我给你选一个
            return new GuanDongZhu1();
        }

这样,每新开一家店,大工厂就要多一个判断,是不是挺麻烦啊。可是不判断呢,我又不知道该创建哪个具体的对象,唉,好烦,不干了!对,不干了——无为

你可能感兴趣的:(设计模式,java,单例模式,简单工厂模式)