常用设计模式一(创建型模式)

2017-07-29  本文已影响0人  老实任

前言

很久前就一直想总结下常用的设计模式,但是各种原因一直拖到现在,下面我尝试用自己的理解去解释常用的设计模式,旨在让自己对常用设计模式有一个直观认识,过后回来能看懂并理解这些常用设计模式,当然如果这篇文章能帮到想了解设计的同学那就更好不过了。


概念介绍

设计模式分为三大类:

这几个模式会在下篇文章中介绍。


单例模式

单例模式是最常用的设计模式之一,是为了保证单例对象的类只有一个实例存在,并保证整个系统只需要拥有一个全局对象。

使用场景

确保某个类在全局中只需要存在一个对象的场景。如:访问IO和数据库时,使用单例模式可以避免浪费资源。

懒汉模式

懒汉模式是声明一个静态变量,在调用对象类提供的get方法时就进行初始化,如下:

public class LazySingleton {
    private static LazySingleton mSingleton;

    public static synchronized LazySingleton getLazySingleton() {
        if (mSingleton == null) {
            mSingleton = new LazySingleton();
        }
        return mSingleton;
    }
}

懒汉模式只会在使用时才会被实例化,可以节约一定的资源,但是每次调用getLazySingleton都会进行同步,造成不必要的同步开销,这种模式一般不建议使用。

饿汉模式

饿汉模式在类加载的时候就进行了初始化,所以类加载会稍慢,但是调用类实例时由于类已经初始化所以获取速度很快。如下:

public class HungrySingleton {
    private static HungrySingleton mSingleton = new HungrySingleton();

    public static HungrySingleton getHungrySingleton() {
        return mSingleton;
    }
}

双重检查模式 (Double CheckLock)

DCL方式的优点是能保证在需要是单例才会初始化的同时保证线程安全。如下:

public class DCLSingleton {

    private static DCLSingleton mSingleton;

    public static DCLSingleton getDCLSingleton() {
        if (mSingleton == null) {
            synchronized (DCLSingleton.class) {
                if (mSingleton == null) {
                    mSingleton = new DCLSingleton();
                }
            }
        }
        return mSingleton;
    }
}

静态内部类单例模式

这种方式不仅能确保线程安全也能保证Singleton类的唯一性,这是推荐使用的静态内部类单例模式。

public class StaticSingleton {
    public static StaticSingleton getStaticSingleton() {
        return StaticSingletonHolder.singleton;
    }

    private static class StaticSingletonHolder {
        private static final StaticSingleton singleton = new StaticSingleton();
    }
}

小结

以上四种是比较常用的单例写法,单例模式在日常开发中使用很多,在Android源码中也有使用。


建造者模式

建造者模式是一步步创建复杂对象的创建型模式,这个模式可以让用户在不知道内部构建细节的情况下,控制对象的构造流程。如汽车有车轮、方向盘、座椅还有各种小零件等,将这些部件组装成一辆汽车就是一个复杂的过程。在这个事例里汽车就是一个复杂的对象,而将汽车部件组装成汽车的过程就是复杂对象的构建流程。建造者模式将复杂对象的构建过程和部件进行了良好的解耦,将耦合度降到最低。

使用场景

例子

使用建造者模式组装一台汽车,假定一辆汽车只需要有车轮、方向盘、座椅这三个部件。那么一个汽车类就有如下几个变量和组装方法:
产品类

public class Car {

    private String mWheel;//车轮
    private String mSteering;//方向盘
    private String mSeat;//座椅

    /**
     * 组装车轮
     *
     * @param mWheel
     */
    public void setmWheel(String mWheel) {
        this.mWheel = mWheel;
    }

    /**
     * 组装方向盘
     *
     * @param mSteering
     */
    public void setmSteering(String mSteering) {
        this.mSteering = mSteering;
    }

    /**
     * 组装座椅
     *
     * @param mSeat
     */
    public void setmSeat(String mSeat) {
        this.mSeat = mSeat;
    }
    
    @Override
    public String toString() {
        return "Car{" +
                "mWheel='" + mWheel + '\'' +
                ", mSteering='" + mSteering + '\'' +
                ", mSeat='" + mSeat + '\'' +
                '}';
    }
}

Builder类组装模板
一个良好的汽车组装流程应该有一套组装模板,模板包含各种控件的组装方法,这里的组装模板类如下

public abstract class Builder {
    public abstract void buildWheel(String wheel);

    public abstract void buildSteering(String settring);

    public abstract void buildSeat(String seat);

    public abstract Car createCar();
}

而要想组装一辆具体的车必须传承这套组装模板:

public class SixSixSixCarBuilder extends Builder {

    private Car mCar = new Car();

    @Override
    public void buildWheel(String wheel) {
        mCar.setmWheel(wheel);
    }

    @Override
    public void buildSteering(String steering) {
        mCar.setmSteering(steering);
    }

    @Override
    public void buildSeat(String seat) {
        mCar.setmSeat(seat);
    }

    @Override
    public Car createCar() {
        return mCar;
    }
}

然后还需要一个指挥者(Director )去规范指挥组装流程:

public class Director {

    Builder mBuild = null;

    public Director(Builder build) {
        this.mBuild = build;
    }

    public Car createCar(String wheel, String steering, String seat) {
        this.mBuild.buildWheel(wheel);
        this.mBuild.buildSteering(steering);
        this.mBuild.buildSeat(seat);
        return mBuild.createCar();
    }

}

这时候谁要造汽车只需要找到这个指挥者即可,测试如下

public class Test{
    public static void main(string[] args){
    
        Builder builder=new SixSixSixCarBuilder();
        Director director=new Director(builder);
        director.createCar("米其林三星轮胎","真皮方向盘","真皮座椅");

        System.out.println("汽车信息:"+builder.createCar().toString());
    }
}

小结

从上面例子得出建造者模式主要有以下几个结构构成:
- Product: 产品类。
- Builder:抽象Builder类,规范产品的组建,子类会继承这个类实现具体的建造流程。

实际开发中Director类经常是忽略的,直接用Builder来对对象进行组装,如下:

public class Test{
    public static void main(string[] args){
        
        Builder builder=new SixSixSixCarBuilder();
        builder.buildWheel("米其林三星轮胎");
        builder.buildSteering("真皮方向盘");
        builder.buildSeat("真皮座椅");
      
        System.out.println("汽车信息:"+builder.createCar().toString());
    }
}

这个Builder一般写成链式调用,这时Builder类的setter方法需要返回自身,如下:

public abstract class Builder {
    public abstract Builder buildWheel(String wheel);

    public abstract Builder buildSteering(String steering);

    public abstract Builder buildSeat(String seat);

    public abstract Car createCar();
}
public class SixSixSixCarBuilder extends Builder {

    private Car mCar = new Car();

    @Override
    public SixSixSixCarBuilder buildWheel(String wheel) {
        mCar.setmWheel(wheel);
        return this;
    }

    @Override
    public SixSixSixCarBuilder buildSteering(String steering) {
        mCar.setmSteering(steering);
        return this;
    }

    @Override
    public SixSixSixCarBuilder buildSeat(String seat) {
        mCar.setmSeat(seat);
        return this;
    }

    @Override
    public Car createCar() {
        return mCar;
    }
}

调用时:

public class Test{
    public static void main(string[] args){

        Builder builder=new SixSixSixCarBuilder();
        builder.buildWheel("米其林三星轮胎")
                .buildSteering("真皮方向盘")
                .buildSeat("真皮座椅") 
                .createCar();
                
        System.out.println("汽车信息:" + builder.createCar().toString());
    }
}

工厂方法模式

工厂方法模式是应用最广泛的模式,它定义一个用于创建对象的接口,让子类决定实例化哪个类。

使用场景

任何需要生成复杂对象的地方都可以使用工厂方法模式。

例子

还是组装汽车,具体组装k3、k5属于同一车型的两款车。由于是同一车型所以一条生产线足够。

先明确汽车需要的功能,即汽车抽象基类:

public abstract class QiYaCar {

    public abstract void drive();//汽车可以开

    public abstract void speedUp();//汽车可以加速
}

创建抽象生产线定义类:

public abstract class QiYaFactory {
    
    /**
     * 
     * @param clzz 具体汽车型号
     * @return 具体的汽车
     */
    public abstract <T extends QiYaCar> T createQiYaCar(Class clzz);
}

创建具体的生产线:

public class QiYaCreateFactory extends QiYaFactory{
    @Override
    public <T extends QiYaCar> T createQiYaCar(Class clzz) {
        QiYaCar car= null;
        try {
            car = (QiYaCar) Class.forName(clzz.getName()).newInstance();
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
        return (T) car;
    }
}

生产具体车型:

public class QiYaK3Car extends QiYaCar{
    @Override
    public void drive() {
        System.out.println("k3启动");
    }

    @Override
    public void speedUp() {
        System.out.println("k3加速");
    }
}
public class QiYaK5Car extends QiYaCar{
    @Override
    public void drive() {
        System.out.println("k5启动");
    }

    @Override
    public void speedUp() {
        System.out.println("k5加速");
    }
}

把上面各个类组装起来就可以形成一条完整的流水线:

public class Client{
    public static void main(string[] args){

        QiYaFactory factory = new QiYaCreateFactory();
        
        QiYaK3Car k3Car = factory.createQiYaCar(QiYaK3Car.class);
        k3Car.drive();
        k3Car.speedUp();

        QiYaK5Car k5Car = factory.createQiYaCar(QiYaK5Car.class);
        k5Car.drive();
        k5Car.speedUp();
    }
}

小结

工厂方法模式是一个很好的设计模式,但是从上面例子也可以看出,工厂方法模式也有一定的缺点,比如当添加新的产品时就要编写一个新的产品类,同时还要引用抽象层,导致类的结构复杂化。是否使用工厂方法模式需要根据实际需求决定。


抽象工厂模式

抽象工厂模式提供一个创建一系列相关或相互依赖对象的接口,而无须指定它们具体的类。抽象工厂模式又称为Kit模式,属于对象创建型模式。

使用场景

一个对象族有相同约束时可以使用抽象工厂模式,如Android、ios都有拨号软件,这个软件属于软件的范畴,但是所在的操作系统不一样,这时候开业考虑使用抽象工厂模式来设计拨号软件。

例子

起亚和现代有两条生成线,一个中型车,一个SUV。抽象工厂模式来进行实现这两条生产线。

首先是抽象产品类:

public abstract class BetweenCar{
  public abstract void drive();//汽车可以开

  public abstract void speedUp();//汽车加速
  
}
public abstract class SUVCar{
   public abstract void drive();//汽车可以开

   public abstract void speedUp();//汽车加速
}

生产具体产品

public class QiYaBetweenCar extends BetweenCar{
    @Override
    public void drive() {
        System.out.println("起亚中型车启动");
    }

    @Override
    public void speedUp() {
        System.out.println("起亚中型车加速");
    }
}
public class XianDaiBetweenCar extends BetweenCar{
    @Override
    public void drive() {
        System.out.println("现代中型车启动");
    }

    @Override
    public void speedUp() {
        System.out.println("现代中型车加速");
    }
}
public class QiYaSUVCar extends SUVCar {
    @Override
    public void drive() {
        System.out.println("起亚SUV启动");
    }

    @Override
    public void speedUp() {
        System.out.println("起亚SUV加速");
    }
}
public class XianDaiSUVCar extends SUVCar {
    @Override
    public void drive() {
        System.out.println("现代SUV启动");
    }

    @Override
    public void speedUp() {
        System.out.println("现代SUV加速");
    }
}

创建生产汽车的抽象工厂里面有两条生产线,即生产中型车和SUV

public abstract class CarFactory {
    
    public abstract BetweenCar createBetweenCar();

    public abstract SUVCar createSUVCar();

}

定义具体的工厂

public class QiYaCarFactory extends CarFactory{
    
    @Override
    public BetweenCar createBetweenCar() {
        return new QiYaBetweenCar();
    }

    @Override
    public SUVCar createSUVCar() {
        return new QiYaSUVCar();
    }
}
public class XianDaiCarFactory extends CarFactory {
    @Override
    public BetweenCar createBetweenCar() {
        return new XianDaiBetweenCar();
    }

    @Override
    public SUVCar createSUVCar() {
        return new XianDaiSUVCar();
    }
}

最后客户端调用

public class Client{
    public static void main(string[] args){

        CarFactory qiYaCarFactory = new QiYaCarFactory();

        qiYaCarFactory.createBetweenCar().drive();
        qiYaCarFactory.createBetweenCar().speedUp();

        qiYaCarFactory.createSUVCar().drive();
        qiYaCarFactory.createSUVCar().speedUp();

        CarFactory xianDaiCarFactory = new XianDaiCarFactory();

        xianDaiCarFactory.createBetweenCar().drive();
        xianDaiCarFactory.createBetweenCar().speedUp();

        xianDaiCarFactory.createSUVCar().drive();
        xianDaiCarFactory.createSUVCar().speedUp();
    }
}

小结

抽象工厂模式一个显著的优点是分离接口与实现,客户端使用抽象工厂来创建需要的对象,而客户端不需要知道具体实现是谁,客户端只是面向产品的接口编程,使其从具体的产品视线中解耦,在切换产品类时更加灵活。当然抽象工厂模式不容易扩展新的产品类,因为增加一个产品类就需要修改抽象工厂,则所有具体工厂类都要修改。

上一篇下一篇

猜你喜欢

热点阅读