设计模式学习笔记(2)——创建型设计模式

一:工厂模式

工厂模式:通过工厂,封装创建对象的代码,不需要具体实例化,使用工厂实例化

(一)简单工厂

1. 定义

又叫做静态工厂方法模式。简单工厂模式是由一个工厂对象决定创建出哪一种产品类的实例。

2. 使用

一个静态方法通过参数,创建需要的对象

  • 抽象产品类
  • 具体产品类
  • 静态工厂类
  • 业务类
    • 具体业务方法:使用静态工厂生产的产品
(1)产品
package FactoryPattern.SimpleFactoryPattern;

/**
 * 抽象产品
 */
public interface Product {
    public void operate();
}

package FactoryPattern.SimpleFactoryPattern;

/**
 * 具体产品A
 */
public class ProductA implements Product{
    @Override
    public void operate() {
        System.out.println("产品A的业务逻辑");
    }
}

package FactoryPattern.SimpleFactoryPattern;

/**
 * 具体产品B
 */
public class ProductB implements Product{
    @Override
    public void operate() {
        System.out.println("产品B的业务逻辑");
    }
}

(2)静态工厂
package FactoryPattern.SimpleFactoryPattern;

/**
 * 静态工厂
 */
public class Factory {
    public static Product createProduct(String type){
        switch (type) {
            case "A":
                return new ProductA();
            case "B":
                return new ProductB();
            default:
                throw new RuntimeException("not found this type!");
        }
    }
}

(3)测试
package FactoryPattern.SimpleFactoryPattern;

public class Test {
    public static void main(String[] args) {
        Product product = Factory.createProduct("A");
        product.operate();
        product = Factory.createProduct("B");
        product.operate();
        product = Factory.createProduct("C");
        product.operate();
    }
}

3. 特点

  • 当系统引入新的产品的时候无需修改业务方法
  • 工厂类集中了所有的创建逻辑,过于臃肿
  • 无法变更正在创建的对象

(二)工厂方法

定义

又叫做虚拟构造子模式或者多态性工厂模式。通过定义创建对象的接口,由子类动态决定实例化,将实际创建工作推迟到子类中。

使用

抽象工厂方法(类的继承)

  • 抽象工厂类
    • 抽象工厂方法:单一产品
  • 具体工厂类
    • 具体工厂方法:创建具体产品
  • 抽象产品类
  • 具体产品类
  • 业务类
    • 具体业务方法:使用抽象工厂类生产的抽象产品
(1)工厂
package FactoryPattern.FactoryFunctionPattern;

/**
 * 抽象工厂
 */
public abstract class Factory {

    public abstract Product createProduct(String type);

}

package FactoryPattern.FactoryFunctionPattern;

/**
 * 具体工厂A——产生A风格的具体产品
 */
public class FactoryA extends Factory {
    @Override
    public Product createProduct(String type) {
        if (type.equals("1"))
            return new ProductA_1();
        else if (type.equals("2"))
            return new ProductA_2();
        else
            throw new RuntimeException("not found this type!");
    }
}

package FactoryPattern.FactoryFunctionPattern;

/**
 * 具体工厂B——产生B风格的具体产品

 */
public class FactoryB extends Factory {
    @Override
    public Product createProduct(String type) {
        if (type.equals("1"))
            return new ProductB_1();
        if (type.equals("2"))
            return new ProductB_2();
        else
            throw new RuntimeException("not found this type!");
    }
}

(2)产品
package FactoryPattern.FactoryFunctionPattern;

/**
 * 抽象产品
 */
public interface Product {
    public void operate();
}

package FactoryPattern.FactoryFunctionPattern;

/**
 * 具体产品A
 */
public class ProductA_1 implements Product {
    @Override
    public void operate() {
        System.out.println("产品A_1的业务逻辑");
    }
}

package FactoryPattern.FactoryFunctionPattern;

/**
 * 具体产品A
 */
public class ProductA_2 implements Product {
    @Override
    public void operate() {
        System.out.println("产品A_2的业务逻辑");
    }
}

package FactoryPattern.FactoryFunctionPattern;

/**
 * 具体产品B
 */
public class ProductB_1 implements Product {
    @Override
    public void operate() {
        System.out.println("产品B_1的业务逻辑");
    }
}

package FactoryPattern.FactoryFunctionPattern;

/**
 * 具体产品B
 */
public class ProductB_2 implements Product {
    @Override
    public void operate() {
        System.out.println("产品B_2的业务逻辑");
    }
}

(3)测试
package FactoryPattern.FactoryFunctionPattern;

public class Test {
    public static void main(String[] args) {
        //使用产品A1的业务
        Factory factory = new FactoryA();
        Product product = factory.createProduct("1");
        product.operate();
        //使用产品B2的业务
        factory = new FactoryB();
        product = factory.createProduct("2");
        product.operate();

    }
}

3. 特点

  • 增加新的产品类型时,系统完全支持“开-闭原则”
  • 允许系统在不修改具体工厂的情况下引进新的产品

(三)抽象工厂

1. 定义

抽象工厂模式:提供一个接口,用于创建相关或依赖对象的产品族,不需要明确具体工厂类

  • 产品族:由位于不同产品等级结构中,功能相关联的产品组成的家族
  • 产品等级结构:由相同的结构的产品组成

2. 使用

  • 抽象工厂接口:相关联的产品组合
    • 多个抽象工厂方法:多个产品
  • 具体工厂
    • 多个实现工厂方法
  • 抽象产品类
  • 具体产品类
  • 业务类
    • 具体业务方法:使用抽象工厂接口生产的抽象产品
(1)工厂
package FactoryPattern.AbstractFactoryPattern;

/**
 * 抽象工厂
 */
public interface Factory {

    //产品结构A的产品
    public ProductA createProductA();

    //产品结构B的产品
    public ProductB createProductB();
}

package FactoryPattern.AbstractFactoryPattern;
/**
 * 具体工厂——实现产品族1
 */
public class Factory1 implements Factory {
    @Override
    public ProductA createProductA() {
        return new ProductA_1();
    }

    @Override
    public ProductB createProductB() {
        return new ProductB_1();
    }
}

package FactoryPattern.AbstractFactoryPattern;

/**
 * 具体工厂——实现产品族2
 */
public class Factory2 implements Factory {
    @Override
    public ProductA createProductA() {
        return new ProductA_2();
    }

    @Override
    public ProductB createProductB() {
        return new ProductB_2();
    }
}

(2)产品
package FactoryPattern.AbstractFactoryPattern;

/**
 * 抽象产品
 */
public interface Product {
    public void operate();
}

package FactoryPattern.AbstractFactoryPattern;

/**
 * 具体产品A
 */
public interface ProductA extends Product {

    public void operateA();
}

package FactoryPattern.AbstractFactoryPattern;

/**
 * 具体产品B
 */
public interface ProductB extends Product {

    public void operateB();
}

package FactoryPattern.AbstractFactoryPattern;

import FactoryPattern.FactoryFunctionPattern.Product;

/**
 * 具体产品A
 */
public class ProductA_1 implements ProductA {
    @Override
    public void operate() {
        System.out.println("产品A_1的基本功能");
    }

    @Override
    public void operateA() {
        System.out.println("产品A_1的特别功能");
    }
}

package FactoryPattern.AbstractFactoryPattern;

import FactoryPattern.FactoryFunctionPattern.Product;

/**
 * 具体产品A
 */
public class ProductA_2 implements ProductA {
    @Override
    public void operate() {
        System.out.println("产品A_2的基本功能");
    }

    @Override
    public void operateA() {
        System.out.println("产品A_2的特别功能");
    }
}

package FactoryPattern.AbstractFactoryPattern;

import FactoryPattern.FactoryFunctionPattern.Product;

/**
 * 具体产品B
 */
public class ProductB_1 implements ProductB {
    @Override
    public void operate() {
        System.out.println("产品B_1的基本功能");
    }

    @Override
    public void operateB() {
        System.out.println("产品B_1的特别功能");
    }
}

package FactoryPattern.AbstractFactoryPattern;

import FactoryPattern.FactoryFunctionPattern.Product;

/**
 * 具体产品B
 */
public class ProductB_2 implements ProductB {
    @Override
    public void operate() {
        System.out.println("产品B_2的基本功能");
    }

    @Override
    public void operateB() {
        System.out.println("产品B_2的特别功能");
    }
}

(3)测试
package FactoryPattern.AbstractFactoryPattern;

public class Test {
    public static void main(String[] args) {
        //组装第1组的产品
        Factory factory1 = new Factory1();
        ProductA a = factory1.createProductA();
        ProductB b = factory1.createProductB();
        a.operateA();
        b.operateB();
        //组装第2组的产品
        Factory factory2 = new Factory2();
        a = factory2.createProductA();
        b = factory2.createProductB();
        a.operateA();
        b.operateB();

    }
}

3. 特点

  • 系统的产品有多于一个的产品族,而系统只需要其中某一族的产品
  • 起到了一定的约束作用,同属于同一个产品族的产品必须配套使用
  • 切换产品族的时候,只要提供不同的抽象工厂实现就可以
  • 不太容易扩展新的产品,需要修改抽象工厂

二:单例模式

1. 定义

确保类中只有一个实例,由自己创建,并且提供一个全局访问点

2. 使用

(1)即时实现(饿汉式)——空间换时间
  • 私有构造器
  • 私有静态变量:初始化为具体对象,记录唯一实例
  • 公共静态构造方法
    • 返回唯一实例
package SingletonPattern;

/**
 * 即时单例
 */
public class ImmediatelySingletion {

    //一开始就创建
    private static ImmediatelySingletion singletion = new ImmediatelySingletion();

    private ImmediatelySingletion(){}

    public static ImmediatelySingletion getInstance(){
        return singletion;
    }
}

(2)延时实现(懒汉式)——时间换空间
  • 私有构造器
  • 私有静态变量:初始化为空值,记录唯一实例
  • 公共静态构造方法:检查是否存在实例
    • 创建唯一实例
    • 返回唯一实例
package SingletonPattern;

/**
 * 延时实现
 */
public class DelayedSingleton {

    //暂未初始化
    private static DelayedSingleton singleton;

    private DelayedSingleton(){}

    public static DelayedSingleton getInstance(){
        if (singleton == null)
            singleton = new DelayedSingleton();
        return singleton;
    }

}

懒汉模式与饿汉模式区别

饿汉模式是最简单的一种实现方式,饿汉模式在类加载的时候就对实例进行创建,实例在整个程序周期都存在。它的好处是只在类加载的时候创建一次实例,不会存在多个线程创建多个实例的情况,避免了多线程同步的问题。

它的缺点也很明显,即使这个单例没有用到也会被创建,而且在类加载之后就被创建,内存就被浪费了。

(3)枚举

单元素的枚举类型已经成为实现Singleton的最佳方法。用枚举来实现单例非常简单,只需要编写一个包含单个元素的枚举类型即可。

package SingletonPattern;

/**
 * 枚举类
 */
public enum  EnumSingleton {

    //枚举单元素
    singleton;

    public void operation(){
        System.out.println("枚举类的业务逻辑");
    }
}

3. 多线程

(1)即时实现
(2)延迟实现

使用synchorized修饰公共静态构造方法

 public static synchronized DelayedSingleton getInstance(){
        if (singleton == null)
            singleton = new DelayedSingleton();
        return singleton;
    }

特点:效率低,在每次创建实例的时候都会同步

(3) 双重检查加锁
  • 使用volatile修饰私有静态变量
  • 公共静态构造方法
    • 第一重检查: 检查是否存在实例
    • 第二重检查:进入同步块过后,再次检查实例是否存在
      • 创建唯一实例
    • 返回唯一实例
package SingletonPattern;

/**
 * 双重加锁检查
 */
public class DuplicationCheck {

    //不会被本地线程缓存
    private static volatile DuplicationCheck singleton;

    private DuplicationCheck(){}

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

}

特点:volatile关键字可能会屏蔽掉虚拟机中一些必要的代码优化,效率较低

双重校验锁方法与线程安全的懒汉模式区别

可以看到双重校验锁方法在同步代码块外多了一层 instance 为空的判断。由于单例对象只需要创建一次,如果后面再次调用 getInstance()只需要直接返回单例对象。因此,大部分情况下,调用 getInstance()都不会执行到同步代码块,从而提高了程序性能。

不过还需要考虑一种情况,假如两个线程 A、B,A 执行了 if (nstance = nul)语句,它会认为单例对象没有创建,此时线程切到 B 也执行了同样的语句,B 也认为单例对象没有创建,然后两个线程依次执行同步代码块,并分别创建了一个单例对象。为了解决这个问题,还需要在同步代码块中增加 if(nstance = nul)语句,也就是上面看到的代码

(4) Lazy initialization holder class模式

类级内部类:由static修饰的成员式内部类
多线程缺省同步锁:由静态初始化器(在静态字段上或static{}块中的初始化器)初始化数据时会自动同步

package SingletonPattern;

/**
 * 通过静态内部类创建对象
 */
public class StaticInnerClass {

    private StaticInnerClass(){}

    /**
     * 被调用时才会加载,由JVM保护线程安全
     */
    private static class holderClass{
        private static StaticInnerClass singleton = new StaticInnerClass();
    }

    public static StaticInnerClass getInstance(){
        return holderClass.singleton;
    }
}

4. 单例模式与静态变量区别

  • 解决引用的唯一实例可能被重新赋值的问题,单例模式中的 getInstance()静态方法实现时,规避了这一风险,无则创建,有则跳过创建
  • 其次,getInstance()静态方法定义在该类的内部,获取该类对象的引用位置非常明确,无需额外的沟通商定,团队成员拿起即用。
  • 最后一个区别并不是很明显,声明一个静态变量,会直接对其进行初始化赋值,这样,在内存占用上,所占用的内存为该初始化赋值对象实际的内存。而单例模式可以通过懒汉创建法延迟该内存的占用,要知道,当一个静态变量只进行声明,而不进行初始化时,实际的内存占用只有 4 个字节

三:生成器模式

1. 定义

将产品的内部结构(零件)与产品的生产过程分割开来,使一个建造过程可以按步骤构造出具有不同结构的产品。

  • 对象:产品
  • 对象的不同性质:产品的不同零件

2. 使用

  • 部分构造
    • 抽象构造者:定义抽象方法,规范产品对象的各个组成零件的建造,提供产品
    • 具体构造者:实现抽象方法,提供具体的产品
    • 具体产品类:具体构造的成果
  • 整体构造
    • 整体构建者:按照确定的步骤,根据不同的构造者构造产品
  • 客户:使用具体构造者,通过整体构建者建造产品
(1)部分构造
package BuildPattern;

/**
 * 抽象建造者
 */
public abstract class Builder {

    //建造步骤
    public void buildA(int param){

    }
    public void buildB(int param){

    }

    //返回产品
    public Product getProduct(){
         return null;
    }
}

package BuildPattern;

/**
 * 具体构造产品A
 */
public class BulderA extends Builder {

    private Product a = new Product();

    @Override
    public void buildA(int param) {
        a.setA(param);
    }

    @Override
    public Product getProduct() {
        return a;
    }
}

package BuildPattern;

/**
 * 具体构造产品B
 */
public class BuilderB extends Builder {
    private Product b = new Product();

    @Override
    public void buildB(int param) {
        b.setB(param);
    }

    @Override
    public Product getProduct() {
        return b;
    }
}

package BuildPattern;

/**
 * 具体产品
 */
public class Product {

    int a = 0;

    int b = 0;

    public int getA() {
        return a;
    }

    public void setA(int a) {
        this.a = a;
    }

    public int getB() {
        return b;
    }

    public void setB(int b) {
        this.b = b;
    }

    @Override
    public String toString() {
        return "Product{" +
                "a=" + a +
                ", b=" + b +
                '}';
    }
}

(2)整体构造
package BuildPattern;

/**
 * 整体构建
 */
public class Director {

    private Builder builder;

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

    public void construct(int a,int b){
        builder.buildA(a);
        builder.buildB(b);
    }
}

(3)测试
package BuildPattern;

public class Test {
    public static void main(String[] args) {
        Builder builder = new BulderA();
        Director director = new Director(builder);
        director.construct(100,100);
        Product product = builder.getProduct();
        System.out.println(product);
    }
}

3. 特点

  • 封装对象的创建过程
  • 隐藏产品内部的结构:每一个内部成分本身可以是对象,也可以仅仅是产品对象的一个组成部分
  • 允许多个步骤创建对象:避免对象的属性相互依赖

四:原型模式

1. 定义

用一个原型对象指明所有创建的对象的类型,然后用复制这个原型对象的办法创建出更多同类型的对象。

2. 使用

(1)简单形式
  • 抽象原型
  • 具体原型:被复制的对象
  • 客户:提出创建对象的请求(明确对象个数)
package PrototypePattern;

/**
 * 抽象接口
 */
public interface Prototype {
    public Object clone();
}

package PrototypePattern;

/**
 * 具体实例
 */
public class PrototypeA implements Prototype {
    @Override
    public Object clone() {
        return new PrototypeA();
    }
}

package PrototypePattern;

public class Test {

    private Prototype prototype;

    public Test(Prototype prototype){
        this.prototype = prototype;
    }

    public Prototype clone(){
        return (Prototype) prototype.clone();
    }

    public static void main(String[] args) {
        Prototype prototype = new PrototypeA();
        Test test = new Test(prototype);
        System.out.println(test.clone());
    }
}

(2)登记形式
  • 抽象原型
  • 具体原型:被复制的对象
  • 客户:提出创建对象的请求(不确定对象个数)
  • 原型管理器:创建具体原型类的对象并记录
package PrototypePattern.RegisterPrototype;

/**
 * 抽象接口
 */
public interface Prototype {
    public Object clone();
    public void setName(String name);
    public String getName();
}

package PrototypePattern.RegisterPrototype;

/**
 * 具体实例
 */
public class PrototypeA implements Prototype {

    private String name;

    @Override
    public Object clone() {
        return new PrototypeA();
    }

    @Override
    public String getName() {
        return name;
    }

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

    @Override
    public String toString() {
        return "PrototypeA{" +
                "name='" + name + '\'' +
                '}';
    }
}

package PrototypePattern.RegisterPrototype;

/**
 * 具体实例
 */
public class PrototypeB implements Prototype {

    private String name;

    @Override
    public Object clone() {
        return new PrototypeB();
    }

    @Override
    public String getName() {
        return name;
    }

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

    @Override
    public String toString() {
        return "PrototypeB{" +
                "name='" + name + '\'' +
                '}';
    }
}

package PrototypePattern.RegisterPrototype;

import java.util.HashMap;
import java.util.Map;

/**
 * 原型管理者
 */
public class PrototypeRegistry {

    private Map<String,Prototype> map;

    public PrototypeRegistry(){
        map = new HashMap<>();
    }

    public void add(String id,Prototype prototype){
        map.put(id,prototype);
    }

    public void remove(String id){
        map.remove(id);
    }

    public Prototype getPrototype(String id){
        Prototype prototype = map.get(id);
        if (prototype != null)
            return (Prototype) prototype.clone();
        return null;
    }

}

package PrototypePattern.RegisterPrototype;

public class Test {
    public static void main(String[] args) {
        PrototypeRegistry registry = new PrototypeRegistry();
        //创建原型
        Prototype a = new PrototypeA();
        Prototype b = new PrototypeB();
        registry.add("a",a);
        registry.add("b",b);
        //获取原型的复制
        Prototype c = registry.getPrototype("a");
        c.setName("我是a的复制");
        System.out.println(c);
        //获取原型的复制
        Prototype d = registry.getPrototype("b");
        d.setName("我是b的复制");
        System.out.println(d);
        Prototype e = registry.getPrototype("c");
        System.out.println(e);

    }
}

3. 特点

  • 隐藏创建对象的复杂性
  • 允许在运行时动态改变具体的实现类型
  • 每一个类都必须配备一个克隆方法

4. JAVA的克隆

(1)条件
  • 克隆对象与原对象不是同一个对象。
  • 克隆对象与原对象的类型相同
  • 如果对象x的equals()方法定义其恰当的话,那么x.clone().equals(x)应当成立
(2)分类
浅度克隆

只负责克隆按值传递的数据(基本数据类型、String类型),而不复制它所引用的对象

实现:Java语言的所有类都会继承一个clone()方法

深度克隆

除了浅度克隆要克隆的值外,还负责克隆引用类型的数据。其他被引用的对象的变量将指向被复制过的新对象

实现:利用序列化实现深度克隆。

  1. 先使对象实现Serializable接口
  2. 将对象序列化
  3. 将对象反序列化
 public  Object deepClone() throws IOException, ClassNotFoundException{
        //将对象写到流里
        ByteArrayOutputStream bos = new ByteArrayOutputStream();
        ObjectOutputStream oos = new ObjectOutputStream(bos);
        oos.writeObject(this);
        //从流里读回来
        ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray());
        ObjectInputStream ois = new ObjectInputStream(bis);
        return ois.readObject();
    }
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值