0
点赞
收藏
分享

微信扫一扫

设计模式(Day01)

ZGtheGreat 2021-09-18 阅读 79

设计模式的类型

1、创建者模式

工厂模式(Factory Pattern)

  1. 简单工厂模式:
    简单工厂模式就是隐藏对象实例化的细节,将对象的创建和实例化操作全都交给一个工厂处理,只需要告诉工厂想要什么样的类就可以了。
    缺点:违背了设计模式的开闭原则,如果需要增加工厂能够实例化的类,必须修改工厂类

实例:Spring

代码实现:

public interface Car {
    void driver();
}

public class Benz implements Car {
    @Override
    public void driver() {
        System.out.println("开奔驰............");
    }
}

public class BMW implements Car {
    @Override
    public void driver() {
        System.out.println("开宝马............");
    }
}

public class LandRover implements Car {
    @Override
    public void driver() {
        System.out.println("开路虎............");
    }
}

public class CarFactory {
    public static Car getCar(String logo){
        if (logo == null){
            return null;
        }
        if ("bmw".equalsIgnoreCase(logo)){
            return new BMW();
        }else if ("benz".equalsIgnoreCase(logo)){
            return new Benz();
        }else if ("landrover".equalsIgnoreCase(logo)){
            return new LandRover();
        }
        return null;
    }
}

public class TestDemo {
    public static void main(String[] args) {
        Car car1 = CarFactory.getCar("BMW");
        car1.driver();
        Car car2 = CarFactory.getCar("Benz");
        car2.driver();
        Car car3 = CarFactory.getCar("LandRover");
        car3.driver();
    }
}

// 运行结果:
开宝马............
开奔驰............
开路虎............

2.工厂方法模式
工厂方法模式就是把简单工厂模式中的工厂设计成一个接口,如果想曾加一个新的类型,直接新建一个新类型的工厂类继承工厂接口,在需要获取实例的时候直接从子工厂获取。(这样就符合了开闭原则

实例:Spring

代码实现:

// 基本的方法不变
public interface CarFactory {
    Car getCar();
}

public class LandRoverCarFactory implements CarFactory{
    @Override
    public Car getCar() {
        return new LandRover();
    }
}

public class BMWCarFactory implements CarFactory{
    @Override
    public Car getCar() {
        return new BMW();
    }
}

public class TestDemo {
    public static void main(String[] args) {
        Car car1 = new LandRoverCarFactory().getCar();
        car1.driver();
        Car car2 = new BMWCarFactory().getCar();
        car2.driver();
    }
}

// 运行结果
开路虎............
开宝马............

抽象工厂模式(Abstract Factory Pattern)

原文链接

单例模式(Singleton Pattern)

重点:构造函数必须是私有的
1.饿汉式(线程安全)
比较常用,但是容易产生垃圾对象(类只要被加载就会new个新对象,浪费内存)
优点:因为没有加锁,所以访问速度比较快。
代码实现:

// 单例模式-饿汉式-线程安全
public class HungryPattern {
    private HungryPattern(){}

    private static HungryPattern instance = new HungryPattern();

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

这个问什么是线程安全的呢?
一般在介绍的时候都是一句话:它基于 classloader 机制避免了多线程的同步问题
那么具体是怎么通过classloader机制避免多线程同步问题的呢?

2.懒汉式(线程不安全)
重点:延迟加载,调用getInstance方法时才创建实例
代码实现:

// 单例模式-懒汉式-线程不安全
public class LazyPattern {
    private static LazyPattern instance = null;

    private LazyPattern(){}
    public static LazyPattern getInstance(){
        if (instance == null){
            instance = new LazyPattern();
        }
        return instance;
    }
}

3.懒汉式(线程安全)
重点:延迟加载,给getInstance方法加锁
缺点:99%情况是不需要加锁的(因为创建成功直接返回instance就可以),浪费性能。
代码实现:

// 单例模式-懒汉式-线程安全
public class LazyPatternSafe {
    private static LazyPatternSafe instance = null;

    private LazyPatternSafe(){}

    public static synchronized LazyPatternSafe getInstance(){
        if (instance == null){
            instance = new LazyPatternSafe();
        }
        return instance;
    }
}

4.双检锁(线程安全)
通过双锁在保证线程安全的同时,还能保证高性能(只有在实例为空的时候才加锁)
代码实现:

// 单例模式-双检锁-线程安全
public class DoubleCheckLocking {
    private volatile static DoubleCheckLocking instance = null;

    private DoubleCheckLocking(){}

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

5.登记式(线程安全)
重点:使用静态内部类
在外部类被加载的时候,内部类不会被加载,只有在调用内部类中的变量的时候才会初始化内部类。也是 基于classloader 机制来保证初始化 instance 时只有一个线程。
在外部类被加载的时候,内部类不会被加载;内部类被加载的时候外部类会被加载。
代码实现:

public class RegisterPattern {

    private static class RegisterPatternHandler{
        private static final RegisterPattern INSTANCE = new RegisterPattern();
    }

    private RegisterPattern(){}
    public static final RegisterPattern getInstance(){
        return RegisterPatternHandler.INSTANCE;
    }
}

6.枚举(线程安全)
暂未研究

public enum EnumPattern {
    INSTANCE;
    public void whateverMethod(){
    }
}

建造者模式/生成器模式(Builder Pattern)

原文链接

原型模式(Prototype Pattern)

1、原型模式是指在已有对象的基础上,使用clone方法克隆出新的对象,而不需要使用new去实例化。
浅克隆和深克隆
浅克隆:克隆的时候会把对象中基本数据类型的值拷贝过去,但是对于对象类型只会复制内存地址,也就是克隆后两个对象中对象类型的数据还是指向同一片内存地址,如果这个内存地址上的内容改变,是会相互影响的。

例如下图,B是A拷贝出来的对象,基本数据类型和String类型拷贝的都是值,但是引用list拷贝的是内存地址,他们还是指向同一片内存地址。



深克隆
深克隆不仅拷贝对象本身和对象中的基本变量,而且拷贝对象包含的引用指向的所有对象
深克隆例子:下面代码中,深克隆后,c1改变了 list的值,但是因为c2中list与c1指向的已经不是一个内存了,所以说c2中list的值并不会改变。

class MyCloneable2 implements Cloneable{
    String name;
    ArrayList<String> list = new ArrayList<String>();

    public MyCloneable2() {
        System.out.println("MyCloneable2对象创建了!!!");
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }

    public String getList() {

        String result = "";
        for (int i = 0; i < list.size(); i++) {
            result += list.get(i);
        }
        return result;
    }

    public void setList(ArrayList<String> list) {
        this.list = list;
    }

    @Override
    public MyCloneable2 clone() {
        MyCloneable2 object = null;
        try {
            object = (MyCloneable2) super.clone();
            object.list = (ArrayList) list.clone();
        } catch (CloneNotSupportedException e) {
            e.printStackTrace();
        }
        return object;
    }
}

public class CloneableDemo {

    public static void main(String[] args) {
        MyCloneable2 c1 = new MyCloneable2();
        ArrayList<String> list = new ArrayList<>();
        list.add("aaa");
        list.add("bbb");

        c1.setList(list);
        MyCloneable2 c2 = c1.clone();
        list.add("ccc");
        System.out.println(c1.getList());
        System.out.println(c2.getList());

    }
}
打印结果:
MyCloneable2对象创建了!!!
aaabbbccc
aaabbb

下面的代码:当直接使用 = 赋值的时候,会直接把c1的引用赋值给c2,那么这两个对象还是指向同一片内存地址,所以当更改了c1的值时,c2的值也会跟着变(同理更改c2,c1也会变)。

class MyCloneable{
    String name;

    public MyCloneable() {
        System.out.println("MyCloneable对象创建了!!!");
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
}

public class CloneableDemo {

    public static void main(String[] args) {
        MyCloneable c1 = new MyCloneable();
        c1.setName("测试");
        MyCloneable c2 = c1;
        c1.setName("嘻嘻");
        System.out.println(c1.getName()); // 嘻嘻
        System.out.println(c2.getName()); // 嘻嘻
        c2.setName("嘿嘿");
        System.out.println(c1.getName());
        System.out.println(c2.getName());
    }
}
输出结果:
MyCloneable对象创建了!!!
嘻嘻
嘻嘻
嘿嘿
嘿嘿

但是当我们使用clone的话就不同了。从下面的代码可以看出,使用clone方法克隆出来的对象是将对象的引用复制了一份,指向了另一片内存,所以当更改c1时,c2的值不会变(同理更改c2,c1也不会变)。另外可以看到,构造方法只打印了一次,也就是说克隆是不会执行构造方法的,单例模式需要使用私有的构造方法,也就是说这两种模式是互斥的。

class MyCloneable implements Cloneable{
    String name;

    public MyCloneable() {
        System.out.println("MyCloneable对象创建了!!!");
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }

    @Override
    public Object clone() {
        Object object = null;
        try {
            object = super.clone();
        } catch (CloneNotSupportedException e) {
            e.printStackTrace();
        }
        return object;
    }
}

public class CloneableDemo {

    public static void main(String[] args) {
        MyCloneable c1 = new MyCloneable();
        c1.setName("测试");
        MyCloneable c2 = (MyCloneable) c1.clone();
        c1.setName("嘻嘻");
        System.out.println(c1.getName());
        System.out.println(c2.getName());
        c2.setName("嘿嘿");
        System.out.println(c1.getName());
        System.out.println(c2.getName());
    }
}
输出结果:
MyCloneable对象创建了!!!
嘻嘻
测试
嘻嘻
嘿嘿
举报

相关推荐

day01

day01 --- hadoop

leetcode day01

JavaScript day01

爬虫day01

day01:HTML 基础

processing集训day01

day01 --- HTML基础

0 条评论