转载

记录一下自己学习的JAVA常用的设计模式

写在前面

设计模式代表了最佳的实践,是众多软件开发前辈经过相当长一段时间的试验和总结出来的理念,是一套被反复使用、经过分门别类的一套问题解决方案。合理的使用设计模式能够保证代码可靠性,让代码更容易被他人理解。足以见得学习设计模式是每一个程序猿的必修课。

给设计模式分个类

设计模式有两种分类方法,也就是根据模式的目的来分和根据模式作用的范围来分。

  • 根据模式的目的来分,可以分为创建型模式、结构型- 模式和行为型模式三种。

    • 创建型模式,描述怎么创建对象,主要特点是将对象的创建和使用剥离,例如单例、工厂模式。
    • 结构型模式,描述如何将类或对象布局成更大的结构,例如代理、适配器模式。
    • 行为型模式,描述类或对象怎么相互协作完成任务,例如观察者、访问者模式。
  • 根据模式的作用范围来分,可以分为类模式和对象模式两种。

    • 类模式,处理类与子类之间的(继承)关系,例如工厂、适配器、模板方法、解释器模式。
    • 对象模式,处理对象之间的关系,除了以上四种之外的所有模式都是对象模式。

1.“寂寞孤独”的单例模式

在JAVA中,每个类都可能拥有多个实例,就像每个人最终都会有多个孩子一样,当然也许你不想生孩子,嫌奶粉钱太贵,这个时候你就可以选择孤独一生——同样的,JAVA中的类也有这种选择,这个时候就要用到单例模式啦。

所谓的单例模式……也就是一个类在jvm虚拟机中只有一个实例。要达成这个需要三个要素。

  • 1.构造方法私有化。
  • 2.静态属性指向实例。
  • 3.public static getInstance方法,返回第二步的静态属性。

尝试使用这三个元素:

public class Singleton {
    //1.私有化构造
    private Singleton(){}
    //2.静态属性指向实例
    private static Singleton instance = new Singleton();
    //3.public static方法,提供静态实例对象
    public static Singleton getInstance(){
        return instance;
    }
}

上面的就是一个典型的单例模式啦,也许你注意到了在这个例子中一旦类加载就会创建实例,就像饿死鬼一样,因此我们叫他饿汉式单例。我们在这个的基础上做一些变化:

public class Singleton {
    //1.私有化构造
    private Singleton(){}
    //2.静态属性指向实例
    private static Singleton instance = null;
    //3.public static方法,提供静态实例对象
    public static Singleton getInstance(){
        if (instance == null){
            return instance = new Singleton();
        }
        return instance;
    }
}

在这个例子中,只有在调用getinstance方法时才会创建实例,懒得动都不想动,要你催他他才不情不愿地创建,这可不就是懒汉嘛。

至于为什么要区分饿汉和懒汉……可能在某些情况下,比如资源较多时,这样加载的时间就会很长……为了避免这样的情况,就可以使用懒汉式了。

另外,如果涉及到线程安全的问题的话,在getInstance方法前加上synchronized就可以啦。

至于用途,很多地方需要有且只有一个实例的时候,就可以使用单例模式了,比如每个人的身份证号、一个班的班长时……

2.工厂模式(普通工厂)

工厂模式是JAVA中最常用的设计模式之一,属于创建型模式,提供了一种创建对象的最佳方式。

在这个模式中,我们创建对象时不会对客户端暴露创建逻辑,而是通过一个共同的接口来指定新创建的对象,就仿佛一个庞大的工厂,嗯,一个创建对象的工厂。

通过实例来感受一下工厂模式↓

/**假如这个工厂是一个汽车厂,首先要有一个汽车接口,里面有一个run方法*/
public interface Car {
    void run();
}
/**奔驰车类实现了汽车接口*/
class Benz implements Car {
    @Override
    public void run() {
        System.out.println("嘟嘟嘟,奔驰车开动啦");
    }
}
/**宝马车类实现了汽车接口*/
public class Bmw implements Car {
    @Override
    public void run() {
        System.out.println("嘟嘟嘟,宝马车启动啦");
    }
}
/**创建汽车的工厂*/
public class CarFactory {
    public Car getCar(String carType){
        if (carType == null){
            return null;
        }
        if (carType.equalsIgnoreCase("Benz")){
            return new Benz();
        }
        if (carType.equalsIgnoreCase("Bmw")){
            return new Bmw();
        }
        return null;
    }
}
/**最后测试,就能通过工厂(CarFactory)来创建汽车(对象)啦*/
public class TestFactory {
    public static void main(String[] args) {
        CarFactory carFactory = new CarFactory();
        Car benz = carFactory.getCar("Benz");
        Car bmw = carFactory.getCar("Bmw");
        benz.run();
        bmw.run();
    }
}

通过上面的例子大概能够感受什么叫做工厂模式了,下面来总结一下优缺点:

  • 优点是只需要对象名就能调用对象、扩展性高、调用者不需要知道实现方式,只要关注接口就行了。
  • 缺点是每次增加一个产品时,就要增加一个具体类和工厂,比如这次是汽车工厂,下次没准就是牙刷工厂、啤酒工厂……显而易见的,代码量和系统复杂度大大增加。

3.抽象工厂模式(超级工厂)

前面的工厂模式考虑的是单一的产品,比如汽车……比如电视,而在抽象工厂模式中,工厂却变成了一个综合形大工厂。

一样的通过实例来感受:

/**一样的汽车接口和汽车实现类*/
public interface Car {...}
class Benz implements Car {...}
public class Bmw implements Car {...}
/**加上另一个需求:游戏机的接口和实现类*/
public interface GameBoy {
    void play();
}
public class PS4 implements GameBoy {
    @Override
    public void play() {
        System.out.println("我要打PS4游戏");
    }
}
public class XBOX implements GameBoy {
    @Override
    public void play() {
        System.out.println("我要打XBOX游戏!");
    }
}

按照工厂模式的套路,这里要开始创建工厂了,有两个需求就要创建两个工厂,然后调用的时候需要自己创建工厂对象,这样显然不符合工厂模式的理念,那么……看来我们需要一个创建工厂的工厂↓

/**和汽车、游戏机的接口一样,也需要一个工厂接口*/
public abstract class AbstractFactory {
    public abstract Car getCar(String carType);
    public abstract GameBoy getGameBoy(String gameBoyType);
}
package com.designpattern.factroypattern;
/**和汽车工厂一样,只不过这是一个创建工厂的工厂*/
public class Factory2Factory {
    public static AbstractFactory getFactory(String factoryType){
        if (factoryType.equalsIgnoreCase("Car")){
            return new CarFactory();
        }
        if (factoryType.equalsIgnoreCase("GameBoy")){
            return new GameBoyFactory();
        }
        return null;
    }
}
/**测试的时候先创建工厂,再创建产品*/
public class TestFactory {
    public static void main(String[] args) {
        AbstractFactory carFactory = Factory2Factory.getFactory("Car");
        Car benz = carFactory.getCar("Benz");
        benz.run();
        AbstractFactory gameBoyFactory = Factory2Factory.getFactory("GameBoy");
        GameBoy ps4 = gameBoyFactory.getGameBoy("PS4");
        ps4.play();
    }
}

所谓的抽象工厂模式,就是对工厂模式的一种变形,只是增加了一个制造工厂的工厂。

  • 优点:既然是工厂模式的变形,当然满足工厂模式的所有优点,此外,还能满足客户端在同一时刻只使用一个工厂产出的对象———如果是用工厂模式来实现这样的需求,那就有问题了。
  • 缺点:如果新增一个工厂类别,需要修改虚拟工厂、实现工厂……所有的工厂类都需要改变,想想都觉得蛋疼。

4.装饰器模式(待更新)

……

原文  https://segmentfault.com/a/1190000022310661
正文到此结束
Loading...