首页 > 其他 > 详细

设计模式(单例、原型、工厂方法、抽象工厂、建造者)

时间:2020-06-08 17:25:23      阅读:33      评论:0      收藏:0      [点我收藏+]

单例模式

创建型模式

  • 单例类只能有一个实例
  • 单例类必须自己创建这个唯一实例
  • 单例类必须给其他对象提供这一实例

1、懒汉式,线程不安全

package org.westos.singleton.demo;

/**
 * @author lwj
 * @date 2020/6/8 10:40
 */
public class Singleton {
    //static 保证唯一
    private static Singleton instance;

    //构造方法私有化
    private Singleton() {}

    //向外部提供一个静态的访问入口
    public static Singleton getInstance() {
        if (instance == null) {
            instance = new Singleton();
            //私有的构造方法只能在本类访问
        }
        return instance;
    }
}

在多线程环境下,有多条语句操作共享变量,容易引发线程不安全问题。

2、懒汉式,线程安全

package org.westos.singleton.demo;

import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;

/**
 * @author lwj
 * @date 2020/6/8 10:40
 */
public class Singleton {
    //static 保证唯一
    private static Singleton instance;

    //构造方法私有化
    private Singleton() {}

    //向外部提供一个静态的访问入口
    public synchronized static Singleton getInstance() {
        System.out.println(Thread.currentThread().getName());
        if (instance == null) {
            instance = new Singleton();
            //私有的构造方法只能在本类访问
        }
        return instance;
    }
}

class MyTest {
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        ExecutorService threadPool = Executors.newFixedThreadPool(2);
        Future<Singleton> submit = threadPool.submit(Singleton::getInstance);
        //将Lambda表达式提高为方法引用
        //提交一个Callable任务
        Singleton singleton = submit.get();
        Future<Singleton> future = threadPool.submit(Singleton::getInstance);
        Singleton singleton1 = future.get();
        System.out.println(singleton == singleton1);

        /*
        pool-1-thread-1
        pool-1-thread-2
        true
         */
        
        threadPool.shutdown();
    }
}

通过synchronized关键字对getInstance方法进行加锁,在方法中永远保持单线程。但是这样会降低效率。

3、饿汉式

线程安全,在类加载的初始化阶段就已经完成了初始化,没有起到Lazy Loading的效果。

package org.westos.singleton.demo2;

/**
 * @author lwj
 * @date 2020/6/8 10:59
 */
public class Singleton {
    private static Singleton instance = new Singleton();

    private Singleton() {}

    public static Singleton getInstance() {
        return instance;
    }
}

4、双重校验锁(Double-Checked Locking)

package org.westos.singleton.demo3;

/**
 * @author lwj
 * @date 2020/6/8 11:04
 */
public class Singleton {
    private static Singleton instance;

    private Singleton() {}

    public static Singleton getInstance() {
        if (instance == null) {
            //判断instance为null时,进入同步代码块,由于是静态方法,没有this,也不能访问Object实例,所以可以用Class对象
            synchronized (Singleton.class) {
                //进入同步代码块,首先重新校验,因为此时有可能instance已经不为null
                if (instance == null) {
                    instance = new Singleton();
                }
            }
        }
        return instance;
    }
}

避免了第二种方式,懒汉式,线程安全的效率低下的问题。

5、静态内部类

package org.westos.singleton.demo4;

/**
 * @author lwj
 * @date 2020/6/8 11:09
 */
public class Singleton {
    //成员内部类的特殊修饰符,private、static,只能访问外部类的静态成员,出了外部类,其他类不能访问
    private static class SingletonHolder {
        private static final Singleton INSTANCE = new Singleton();
    }

    private Singleton() {}

    public static Singleton getInstance() {
        return SingletonHolder.INSTANCE;
    }
}

相比第三种方式,饿汉式是加载Singleton类,instance实例就被初始化了,而静态内部类的方式,加载Singleton类不会导致instance的初始化,只有主动调用了getInstance的静态方法,才会加载SingletonHolder类。

和饿汉式一样,都是利用了classloader加载类的机制,保证线程安全。

原型模式

用一个已经创建的实例作为原型,通过复制该原型对象来创建一个和原型相同或相似的新对象。

原型模式的克隆分为浅克隆和深克隆。

Java 中的 Object 类提供了浅克隆的 clone() 方法,具体原型类只要实现 Cloneable 接口就可实现对象的浅克隆。

浅克隆

package org.westos.prototype;

/**
 * @author lwj
 * @date 2020/6/8 11:30
 */
public class Address {
    private String province;
    private String city;

    public Address() {
        System.out.println("无参构造执行了");
    }

    public Address(String province, String city) {
        this.province = province;
        this.city = city;
    }

    public String getProvince() {
        return province;
    }

    public void setProvince(String province) {
        this.province = province;
    }

    public String getCity() {
        return city;
    }

    public void setCity(String city) {
        this.city = city;
    }
}
package org.westos.prototype;

/**
 * @author lwj
 * @date 2020/6/8 11:35
 */
public class Student implements Cloneable {
    private String name;
    private int age;
    private Address address;

    public Student() {
        System.out.println("无参构造执行了");
    }

    public Student(String name, int age, Address address) {
        this.name = name;
        this.age = age;
        this.address = address;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public Address getAddress() {
        return address;
    }

    public void setAddress(Address address) {
        this.address = address;
    }

    @Override
    protected Object clone() throws CloneNotSupportedException {
        return super.clone();
    }
}

测试类

package org.westos.prototype;

/**
 * @author lwj
 * @date 2020/6/8 11:37
 */
public class MyTest {
    public static void main(String[] args) throws CloneNotSupportedException {
        //浅克隆
        Address address = new Address("陕西", "西安");
        Student student = new Student("张三", 23, address);

        Student clone = (Student) student.clone();

        System.out.println(student == clone);
        //false
        System.out.println(student.getAddress() == clone.getAddress());
        //true
        //如果存在引用类型的成员属性,在浅克隆时只是复制引用地址,赋给clone对象

        student.getAddress().setCity("杨凌");

        System.out.println(clone.getAddress().getCity());
        //杨凌
        //修改student对象,clone对象也被修改了
    }
}

采用Object类的clone方法,和new一个对象不同,所以不会执行构造方法。

深克隆

深克隆,相比浅克隆,会复制引用类型成员的内容,而不仅仅是复制引用地址。

package org.westos.prototype;

/**
 * @author lwj
 * @date 2020/6/8 11:30
 */
public class Address implements Cloneable {
    private String province;
    private String city;

    public Address() {
        System.out.println("无参构造执行了");
    }

    public Address(String province, String city) {
        this.province = province;
        this.city = city;
    }

    public String getProvince() {
        return province;
    }

    public void setProvince(String province) {
        this.province = province;
    }

    public String getCity() {
        return city;
    }

    public void setCity(String city) {
        this.city = city;
    }

    @Override
    protected Object clone() throws CloneNotSupportedException {
        return super.clone();
    }
}
package org.westos.prototype;

/**
 * @author lwj
 * @date 2020/6/8 11:35
 */
public class Student implements Cloneable {
    private String name;
    private int age;
    private Address address;

    public Student() {
        System.out.println("无参构造执行了");
    }

    public Student(String name, int age, Address address) {
        this.name = name;
        this.age = age;
        this.address = address;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public Address getAddress() {
        return address;
    }

    public void setAddress(Address address) {
        this.address = address;
    }

    @Override
    protected Object clone() throws CloneNotSupportedException {
        Student clone = (Student) super.clone();
        //复制引用成员
        clone.address = (Address) clone.address.clone();
        return clone;
    }
}

测试类

package org.westos.prototype;

/**
 * @author lwj
 * @date 2020/6/8 11:48
 */
public class MyDemo {
    public static void main(String[] args) throws CloneNotSupportedException {
        //深克隆
        Address address = new Address("浙江", "杭州");
        Student student = new Student("李四", 24, address);

        Student clone = (Student) student.clone();

        System.out.println(student == clone);
        //false
        System.out.println(student.getAddress() == clone.getAddress());
        //false

        student.getAddress().setCity("温州");

        System.out.println(clone.getAddress().getCity());
        //杭州
        //修改原先的student对象不影响clone对象
    }
}

工厂方法模式

定义一个创建产品对象的工厂接口,将产品对象的实际创建工作推迟到具体子工厂类当中。

如果要创建的产品不多,只要一个工厂类就可以完成,这种模式叫“简单工厂模式”,它不属于 GoF 的 23 种经典设计模式,它的缺点是增加新产品时会违背“开闭原则”。

工厂方法模式由抽象工厂、具体工厂、抽象产品和具体产品等4个要素构成。

package org.westos.factorymethod;

/**
 * @author lwj
 * @date 2020/6/8 11:57
 */
public abstract class Animal {
    public abstract void show();
}

class Horse extends Animal {

    @Override
    public void show() {
        System.out.println("新马诞生");
    }
}

class Cattle extends Animal {

    @Override
    public void show() {
        System.out.println("新牛诞生");
    }
}
package org.westos.factorymethod;

/**
 * @author lwj
 * @date 2020/6/8 12:00
 */
public abstract class AnimalFactory {
    public abstract Animal getAnimal();
}

class HorseFactory extends AnimalFactory {

    @Override
    public Animal getAnimal() {
        return new Horse();
    }
}

class CattleFactory extends AnimalFactory {

    @Override
    public Animal getAnimal() {
        return new Cattle();
    }
}

测试类

package org.westos.factorymethod;

/**
 * @author lwj
 * @date 2020/6/8 12:02
 */
public class MyTest {
    public static void main(String[] args) {
        AnimalFactory factory = new HorseFactory();
        Horse horse = (Horse) factory.getAnimal();
        horse.show();
        //新马诞生

        AnimalFactory cattleFactory = new CattleFactory();
        Cattle cattle = (Cattle) cattleFactory.getAnimal();
        cattle.show();
        //新牛诞生
    }
}

抽象工厂模式

前面的工厂方法模式,考虑的是一类产品的生产,如畜牧场只生产动物。

即工厂方法模式只考虑生产同等级的产品。

抽象工厂模式将考虑多等级产品的生产,将同一个具体工厂所生产的位于不同等级的一组产品称为一个产品族,图

所示的是海尔工厂和 TCL 工厂所生产的电视机与空调对应的关系图。

技术分享图片

package org.westos.abstractfactory;

/**
 * @author lwj
 * @date 2020/6/8 13:39
 */
public abstract class TV {
    public abstract void show();
}

class HaierTV extends TV {

    @Override
    public void show() {
        System.out.println("海尔TV播放电视");
    }
}

class TCLTV extends TV {

    @Override
    public void show() {
        System.out.println("TCL电视播放电视");
    }
}
package org.westos.abstractfactory;

/**
 * @author lwj
 * @date 2020/6/8 13:41
 */
public abstract class AirCondition {
    public abstract void show();
}

class HaierAirCondition extends AirCondition {

    @Override
    public void show() {
        System.out.println("海尔空调制冷");
    }
}

class TCLAirCondition extends AirCondition {

    @Override
    public void show() {
        System.out.println("TCL空调制冷");
    }
}
package org.westos.abstractfactory;

/**
 * @author lwj
 * @date 2020/6/8 13:44
 */
public abstract class AbstractFactory {
    public abstract TV newTV();
    public abstract AirCondition newAirCondition();
}

class HaierFactory extends AbstractFactory {

    @Override
    public TV newTV() {
        return new HaierTV();
    }

    @Override
    public AirCondition newAirCondition() {
        return new HaierAirCondition();
    }
}

class TCLFactory extends AbstractFactory {

    @Override
    public TV newTV() {
        return new TCLTV();
    }

    @Override
    public AirCondition newAirCondition() {
        return new TCLAirCondition();
    }
}
package org.westos.abstractfactory;

/**
 * @author lwj
 * @date 2020/6/8 13:33
 */
public class MyTest {
    public static void main(String[] args) {
        AbstractFactory haierFactory = new HaierFactory();
        haierFactory.newTV().show();
        //海尔TV播放电视
        haierFactory.newAirCondition().show();
        //海尔空调制冷

        AbstractFactory tclFactory = new TCLFactory();
        tclFactory.newTV().show();
        //TCL电视播放电视
        tclFactory.newAirCondition().show();
        //TCL空调制冷
    }
}

建造者模式

建造者模式(Builder):它是将一个复杂的对象分解为多个简单的对象,然后一步一步构建而成。将变与不变

相分离,即产品的组成部分是不变的,但每一部分是可以灵活选择的。

建造者(Builder)模式由产品、抽象建造者、具体建造者、指挥者等 4 个要素构成。

技术分享图片

用建造者(Builder)模式描述客厅装修。

产品

package org.westos.builder;

/**
 * @author lwj
 * @date 2020/6/8 16:17
 */
public class LivingRoom {
    private String wall;
    private String tv;
    private String sofa;

    public void setWall(String wall) {
        this.wall = wall;
    }

    public void setTv(String tv) {
        this.tv = tv;
    }

    public void setSofa(String sofa) {
        this.sofa = sofa;
    }

    @Override
    public String toString() {
        return "LivingRoom{" +
                "wall=‘" + wall + ‘\‘‘ +
                ", tv=‘" + tv + ‘\‘‘ +
                ", sofa=‘" + sofa + ‘\‘‘ +
                ‘}‘;
    }
}

抽象建造者

package org.westos.builder;

/**
 * @author lwj
 * @date 2020/6/8 16:18
 */
public abstract class Builder {
    //抽象建造者
    protected LivingRoom livingRoom = new LivingRoom();

    public abstract void buildWall();

    public abstract void buildTV();

    public abstract void buildSofa();

    public LivingRoom getResult() {
        return livingRoom;
    }
}

具体建造者

package org.westos.builder;

/**
 * @author lwj
 * @date 2020/6/8 16:21
 */
public class ConcreteBuilder extends Builder {
    @Override
    public void buildWall() {
        livingRoom.setWall("墙布");
    }

    @Override
    public void buildTV() {
        livingRoom.setTv("小米电视");
    }

    @Override
    public void buildSofa() {
        livingRoom.setSofa("全友家居沙发");
    }
}

指挥者

package org.westos.builder;

/**
 * @author lwj
 * @date 2020/6/8 16:22
 */
public class Director {
    //建造者
    private Builder builder;

    public Director(Builder builder) {
        this.builder = builder;
    }

    public LivingRoom construct() {
        builder.buildWall();
        builder.buildTV();
        builder.buildSofa();
        return builder.getResult();
    }
}

测试类

package org.westos.builder;

/**
 * @author lwj
 * @date 2020/6/8 16:24
 */
public class MyTest {
    public static void main(String[] args) {
        Builder builder = new ConcreteBuilder();
        Director director = new Director(builder);
        LivingRoom livingRoom = director.construct();
        System.out.println(livingRoom);
        //LivingRoom{wall=‘墙布‘, tv=‘小米电视‘, sofa=‘全友家居沙发‘}

        //Director(Builder builder)
    }
}

设计模式(单例、原型、工厂方法、抽象工厂、建造者)

原文:https://www.cnblogs.com/shawnyue-08/p/13066538.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!