【设计模式①】单例、原型、工厂方法、抽象工厂模式

环境

Java:1.8.0_202-b08
dependency:

1. 单例模式

a). 定义:

Java中单例模式定义:“一个类有且仅有一个实例,并且自行实例化向整个系统提供。”

b). 实现

请看注释

package io.ilss.pattern.singleton;

/**
 * @author : feng
 * @description: SingletonThree
 * @date : 2019-04-11 15:42
 * @version: : 1.0
 */
public class SingletonOne {

    private final static SingletonOne INSTANCE = new SingletonOne();

    private SingletonOne(){}

    public static SingletonOne getInstance(){
        return INSTANCE;
    }

    /**
     * 第一种:饿汉式 使用静态常量直接new
     *
     * 在类加载的时候,完成实例,可以避免线程同步问题
     */
}

package io.ilss.pattern.singleton;

/**
 * @author : feng
 * @description: SingletonThree
 * @date : 2019-04-11 15:54
 * @version: : 1.0
 */
public class SingletonTwo {
    private final static SingletonTwo INSTANCE;

    static {
        INSTANCE = new SingletonTwo();
    }

    private SingletonTwo() {}

    public static SingletonTwo getInstance() {
        return INSTANCE;
    }

    /**
     * 第二种:饿汉式 使用静态代码块
     *
     * 和第一种类似
     */
}

package io.ilss.pattern.singleton;

/**
 * @author : feng
 * @description: SingletonThree
 * @date : 2019-04-11 16:01
 * @version: : 1.0
 */
public class SingletonThree {
    private static SingletonThree SingletonThree;

    private SingletonThree() {}

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

    /**
     * 第三种:懒汉式 通过getInstance方法中空判断来实现
     *
     * 注:此种方法线程不安全,多线程情况 不推荐使用。
     *
     */
}

package io.ilss.pattern.singleton;

/**
 * @author : feng
 * @description: SingletonFour
 * @date : 2019-04-11 16:11
 * @version: : 1.0
 */
public class SingletonFour {

    private static SingletonFour INSTANCE;

    private SingletonFour() {
    }

    public static synchronized SingletonFour getInstance() {
        if (null == INSTANCE) {
            INSTANCE = new SingletonFour();
        }
        return INSTANCE;
    }

    /**
     * 第四种:懒汉式 使用synchronized同步锁实现
     *
     * 因为使用了方法级锁,效率偏低。
     */
}

package io.ilss.pattern.singleton;

/**
 * @author : feng
 * @description: SingletonFive
 * @date : 2019-04-11 16:17
 * @version: : 1.0
 */
public class SingletonFive {

    private static SingletonFive INSTANCE;

    private SingletonFive() { }

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

    /**
     * 第五种 懒汉式 使用double-check(双重检查机制)
     *
     * 延迟加载,线程安全。 推荐使用
     */
}

package io.ilss.pattern.singleton;

/**
 * @author : feng
 * @description: SingletonSix
 * @date : 2019-04-12 09:27
 * @version: : 1.0
 */
public class SingletonSix {
    private static class Singleton {
        private static SingletonSix INSTANCE = new SingletonSix();
    }

    public static SingletonSix getInstance() {
        return Singleton.INSTANCE;
    }
    /**
     * 第六种 静态内部类
     *
     * 采用类装载的机制来保证初始化实例时只有一个线程。
     * 静态内部类方式在Singleton类被装载时并不会立即实例化,
     * 而是在需要实例化时,调用getInstance方法,才会装载Singleton类,
     * 从而完成SingletonSix的实例化。
     */
}

package io.ilss.pattern.singleton;

/**
 * @author : feng
 * @description: SingletonSeven
 * @date : 2019-04-12 09:31
 * @version: : 1.0
 */
public class SingletonSeven {
    public String string = "test";
    // 内部枚举类
    private enum EnumSingleton{
        // 规范要求必须有注释。。请忽略这个注释,好吧 既然你看完了,那就再看两眼?
        Singleton;
        private SingletonSeven instance;

        // 枚举类的构造方法在类加载时被实例化
        EnumSingleton(){
            instance = new SingletonSeven();
        }
        private SingletonSeven getInstance(){
            return instance;
        }
    }
    public static SingletonSeven getInstance() {
        return EnumSingleton.Singleton.getInstance();
    }


    /**
     * 第七种:通过内部枚举类实现
     *
     * Java保证了所有枚举的构造方法只会被执行一次,所以无论多少线程调用,都只会产生一个实例。
     */
}

2. 原型模式

a). 定义

原型模式就是用原型实例指定创建对象的种类,并且通过复制这些原型创建新的对象。

浅拷贝:使用一个已知实例对新创建实例的成员变量逐个赋值,这个方式被称为浅拷贝。

深拷贝:当一个类的拷贝构造方法,不仅要复制对象的所有非引用成员变量值,还要为引用类型的成员变量创建新的实例,并且初始化为形式参数实例值。

关于浅拷贝和深拷贝 可以看 http://www.cnblogs.com/chenssy/p/3308489.html

b). 实现

package io.ilss.pattern.prototype;

import lombok.Data;
import lombok.Getter;
import lombok.Setter;
import lombok.extern.slf4j.Slf4j;

/**
 * @author : feng
 * @description: SomeObject
 * @date : 2019-04-12 14:11
 * @version: : 1.0
 */
@Getter
@Setter
@Slf4j
public class SomeObject implements Cloneable {
    private int flag = 1;
    private String msg = "hello world!";

    /**
     * Java中的Object类提供了浅克隆的clone()方法,
     * 具体原型类只要实现 Cloneable 接口就可实现对象的浅克隆
     */
    @Override
    protected Object clone() throws CloneNotSupportedException {
        return super.clone();
    }

    public static void main(String[] args) throws CloneNotSupportedException {
        SomeObject object1 = new SomeObject();
        SomeObject object2 = (SomeObject) object1.clone();
        SomeObject object3 = (SomeObject) object1.clone();
        object3.setFlag(2);
        log.debug(" object 1 : {} , hashCode() : {} , toString() : {} ", object1, object1.hashCode(), object1.getMsg() + " " + object1.getFlag());
        log.debug(" object 2 : {} , hashCode() : {} , toString() : {} ", object2, object2.hashCode(), object2.getMsg() + " " + object2.getFlag());
        log.debug(" object 3 : {} , hashCode() : {} , toString() : {} ", object3, object3.hashCode(), object3.getMsg() + " " + object3.getFlag());

    }
}

②用带原型管理器的原型模式来生成包含“圆”和“正方形”等图形的原型

package io.ilss.pattern.prototype;

/**
 * @author : feng
 * @description: Shape
 * @date : 2019-04-12 14:42
 * @version: : 1.0
 */
interface Shape extends Cloneable {
    /**
     * 拷贝
     * @return Object
     */
    Object clone();

    /**
     * 计算面积
     * @return area
     */
    double computeArea();

}
package io.ilss.pattern.prototype;

import lombok.Getter;
import lombok.Setter;
import lombok.extern.slf4j.Slf4j;

import java.util.Scanner;

/**
 * @author : feng
 * @description: Circle
 * @date : 2019-04-12 14:44
 * @version: : 1.0
 */

@Getter
@Setter
@Slf4j
public class Circle implements Shape {
    double radius = 1.0;
    @Override
    public Object clone() {
        Circle circle = null;
        try {
            circle = (Circle) super.clone();
        } catch (CloneNotSupportedException e) {
            log.error("Clone Circle class failed!");
        }
        return circle;
    }

    @Override
    public double computeArea() {
        return Math.PI * radius * radius;
    }
}
package io.ilss.pattern.prototype;

import lombok.Getter;
import lombok.Setter;
import lombok.extern.slf4j.Slf4j;

/**
 * @author : feng
 * @description: Square
 * @date : 2019-04-12 14:48
 * @version: : 1.0
 */
@Getter
@Setter
@Slf4j
class Square implements Shape {
    private double length = 1.0;
    @Override
    public Object clone() {
        Square square = null;
        try {
            square = (Square) super.clone();
        } catch (CloneNotSupportedException e) {
            log.error("Clone Square class failed!");
        }
        return square;
    }

    @Override
    public double computeArea() {
        return length * length;
    }

}
package io.ilss.pattern.prototype;

import com.google.common.collect.Maps;
import lombok.extern.slf4j.Slf4j;

import java.util.*;

/**
 * @author : feng
 * @description: PrototypeManager
 * @date : 2019-04-12 14:42
 * @version: : 1.0
 */
@Slf4j
class PrototypeManager {
    private Map<String, Shape> map = Maps.newHashMap();

    public PrototypeManager() {
        map.put("Circle", new Circle());
        map.put("Square", new Square());
    }

    public void addshape(String key, Shape obj) {
        map.put(key, obj);
    }

    public Shape getShape(String key) {
        Shape temp = map.get(key);
        return (Shape) temp.clone();
    }

    public static void main(String[] args) {
        PrototypeManager manager = new PrototypeManager();
        Shape object1 = manager.getShape("Circle");
        log.debug(" {} ", object1.computeArea());

        Shape object2 = manager.getShape("Square");
        log.debug(" {} ", object2.computeArea());

        Circle circle = (Circle) manager.getShape("Circle");
        circle.setRadius(2.2);
        Shape object3 = circle;
        log.debug(" {} ", object3.computeArea());

    }
}

3. 工厂方法模式

a). 定义

工厂方法模式是简单工厂模式的衍生,解决了许多简单工厂模式的问题。首先完全实现‘开-闭 原则’,实现了可扩展。其次更复杂的层次结构,可以应用于产品结果复杂的场合。

简单工厂模式是属于创建型模式。简单工厂模式是由一个工厂对象决定创建出哪一种产品类的实例。
简单工厂模式是工厂模式中最简单实用的模式,可以理解为是不同工厂模式的一个特殊实现。
简单工厂模式又称静态工厂方法模式。它存在的目的很简单:定义一个用于创建对象的接口。

工厂方法模式中考虑的是一类产品的生产,如畜牧场只养动物、电视机厂只生产电视机、计算机软件学院只培养计算机软件专业的学生

工厂方法模式的主要角色如下。

  • 抽象工厂(Abstract Factory):提供了创建产品的接口,调用者通过它访问具体工厂的工厂方法 newProduct() 来创建产品。
  • 具体工厂(ConcreteFactory):主要是实现抽象工厂中的抽象方法,完成具体产品的创建。
  • 抽象产品(Product):定义了产品的规范,描述了产品的主要特性和功能。
  • 具体产品(ConcreteProduct):实现了抽象产品角色所定义的接口,由具体工厂来创建,它同具体工厂之间一一对应。


    在这里插入图片描述

b). 实现

Product

package io.ilss.pattern.factorymethod;

/**
 * @author : feng
 * @description: Product 抽象产品
 * @date : 2019-04-12 16:10
 * @version: : 1.0
 */
interface Product {
    public void show();
}
ConcreteProduct

package io.ilss.pattern.factorymethod;

import lombok.extern.slf4j.Slf4j;

/**
 * @author : feng
 * @description: ConcreteProductOne 产品1
 * @date : 2019-04-12 16:11
 * @version: : 1.0
 */
@Slf4j
class ConcreteProductOne implements Product {
    private String name = "One";
    @Override
    public void show() {
        log.info("Product {} show()", name);
    }
}
package io.ilss.pattern.factorymethod;

import lombok.extern.slf4j.Slf4j;

/**
 * @author : feng
 * @description: ConcreteProductOne 产品2
 * @date : 2019-04-12 16:11
 * @version: : 1.0
 */
@Slf4j
class ConcreteProductTwo implements Product {
    private String name = "Two";
    @Override
    public void show() {
        log.info("Product {} show()", name);
    }
}

AbstractFactory

package io.ilss.pattern.factorymethod;

/**
 * @author : feng
 * @description: ProductAbstractFactory 抽象工厂
 * @date : 2019-04-12 16:13
 * @version: : 1.0
 */
public interface ProductAbstractFactory {

    /**
     * 生产产品
     * @return Product
     */
    Product newProduct();

}

ConcreteFactory

package io.ilss.pattern.factorymethod;

/**
 * @author : feng
 * @description: ProductConcreteOneFactory 具体工厂1
 * @date : 2019-04-12 16:15
 * @version: : 1.0
 */
public class ProductConcreteOneFactory implements ProductAbstractFactory {

    @Override
    public Product newProduct() {
        return new ConcreteProductOne();
    }
}
package io.ilss.pattern.factorymethod;

/**
 * @author : feng
 * @description: ProductConcreteTwoFactory 具体工厂2
 * @date : 2019-04-12 16:16
 * @version: : 1.0
 */
public class ProductConcreteTwoFactory implements ProductAbstractFactory {
    @Override
    public Product newProduct() {
        return new ConcreteProductTwo();
    }
}

4. 抽象工厂模式

a). 定义

  • 抽象工厂模式是所有形态的工厂模式中最为抽象和最具一般性的一种形态。抽象工厂模式是指当有多个抽象角色时,使用的一种工厂模式。抽象工厂模式可以向客户端提供一个接口,使客户端在不必指定产品的具体的情况下,创建多个产品族中的产品对象。根据里氏替换原则,任何接受父类型的地方,都应当能够接受子类型。因此,实际上系统所需要的,仅仅是类型与这些抽象产品角色相同的一些实例,而不是这些抽象产品的实例。换言之,也就是这些抽象产品的具体子类的实例。工厂类负责创建抽象产品的具体子类的实例。

里氏替换原则:

  • 里氏替换原则(Liskov Substitution Principle LSP)面向对象设计的基本原则之一。 里氏替换原则中说,任何基类可以出现的地方,子类一定可以出现。 LSP是继承复用的基石,只有当衍生类可以替换掉基类,软件单位的功能不受到影响时,基类才能真正被复用,而衍生类也能够在基类的基础上增加新的行为。

如此,问题产生了:“我们如何去度量继承关系的质量?”

Liskov于1987年提出了一个关于继承的原则** “Inheritance should ensure that any property proved about supertype objects also holds for subtype objects.”——“继承必须确保超类所拥有的性质在子类中仍然成立。” **也就是说,当一个子类的实例应该能够替换任何其超类的实例时,它们之间才具有is-A关系。

该原则称为Liskov Substitution Principle——里氏替换原则。

  • 抽象工厂是一种为访问类提供一个创建一组相关或相互依赖对象的接口,且访问类无须指定所要产品的具体类就能得到同族的不同等级的产品的模式结构。

  • 抽象工厂模式是工厂方法模式的升级版本,工厂方法模式只生产一个等级的产品,而抽象工厂模式可生产多个等级的产品。

b). 实现

在这里插入图片描述
package io.ilss.pattern.abstractfactory;

/**
 * @author : feng
 * @description: ProductOne 抽象产品 1
 * @date : 2019-04-12 16:10
 * @version: : 1.0
 */
interface ProductOne {
    public void show();
}


package io.ilss.pattern.abstractfactory;

/**
 * @author : feng
 * @description: ProductOne 抽象产品 2
 * @date : 2019-04-12 16:10
 * @version: : 1.0
 */
interface ProductTwo {
    public void show();
}
package io.ilss.pattern.abstractfactory;

import lombok.extern.slf4j.Slf4j;

/**
 * @author : feng
 * @description: ConcreteProductOneOne 产品1 厂商1
 * @date : 2019-04-12 16:46
 * @version: : 1.0
 */
@Slf4j
public class ConcreteProductOneOne implements ProductOne {
    private String name = "OneOne";
    @Override
    public void show() {
        log.info("Product {} show()", name);
    }
}
package io.ilss.pattern.abstractfactory;

import lombok.extern.slf4j.Slf4j;

/**
 * @author : feng
 * @description: ConcreteProductOneTwo 产品1 厂商2
 * @date : 2019-04-12 16:46
 * @version: : 1.0
 */
@Slf4j
public class ConcreteProductOneTwo implements ProductOne {
    private String name = "OneTwo";
    @Override
    public void show() {
        log.info("Product {} show()", name);

    }
}
package io.ilss.pattern.abstractfactory;

import lombok.extern.slf4j.Slf4j;

/**
 * @author : feng
 * @description: ConcreteProductTwoOne 产品2 厂商1
 * @date : 2019-04-12 16:46
 * @version: : 1.0
 */
@Slf4j
public class ConcreteProductTwoOne implements ProductTwo {
    private String name = "TwoOne";
    @Override
    public void show() {
        log.info("Product {} show()", name);

    }
}
package io.ilss.pattern.abstractfactory;

import lombok.extern.slf4j.Slf4j;

/**
 * @author : feng
 * @description: ConcreteProductTwoTwo 产品2 厂商2
 * @date : 2019-04-12 16:46
 * @version: : 1.0
 */
@Slf4j
public class ConcreteProductTwoTwo implements ProductTwo {
    private String name = "TwoTwo";
    @Override
    public void show() {
        log.info("Product {} show()", name);

    }
}
package io.ilss.pattern.abstractfactory;

/**
 * @author : feng
 * @description: AbstractFactory 抽象工厂
 * @date : 2019-04-12 16:43
 * @version: : 1.0
 */
interface AbstractFactory
{
    public ProductOne newProductOne();
    public ProductTwo newProductTwo();
}
package io.ilss.pattern.abstractfactory;

/**
 * @author : feng
 * @description: ProductConcreteOneFactory 工厂1
 * @date : 2019-04-12 16:44
 * @version: : 1.0
 */
public class ProductConcreteOneFactory {
    public ProductOne newProductOne() {
        return new ConcreteProductOneOne();
    }

    public ProductTwo newProductTwo() {
        return new ConcreteProductTwoOne();
    }
}
package io.ilss.pattern.abstractfactory;

/**
 * @author : feng
 * @description: ProductConcreteTwoFactory 工厂2
 * @date : 2019-04-12 16:44
 * @version: : 1.0
 */
public class ProductConcreteTwoFactory {
    public ProductOne newProductOne() {
        return new ConcreteProductOneTwo();
    }

    public ProductTwo newProductTwo() {
        return new ConcreteProductTwoTwo();
    }
}

参考文章

  1. http://c.biancheng.net/view/1343.html
  2. https://baike.baidu.com/item/%E5%8E%9F%E5%9E%8B%E6%A8%A1%E5%BC%8F/4941014?fr=aladdin
  3. https://www.cnblogs.com/zhaoyan001/p/6365064.html
  4. http://www.cnblogs.com/garryfu/p/7976546.html
  5. http://c.biancheng.net/view/1348.html
  6. https://baike.baidu.com/item/%E5%B7%A5%E5%8E%82%E6%96%B9%E6%B3%95%E6%A8%A1%E5%BC%8F/2361103?fr=aladdin
  7. http://www.cnblogs.com/forlina/archive/2011/06/21/2086114.html
  8. https://baike.baidu.com/item/%E6%8A%BD%E8%B1%A1%E5%B7%A5%E5%8E%82%E6%A8%A1%E5%BC%8F
  9. http://c.biancheng.net/view/1351.html
  10. https://www.jianshu.com/p/7deb64f902db
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,793评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,567评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,342评论 0 338
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,825评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,814评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,680评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,033评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,687评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 42,175评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,668评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,775评论 1 332
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,419评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,020评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,978评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,206评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,092评论 2 351
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,510评论 2 343

推荐阅读更多精彩内容

  • 文章部分内容转载自:http://blog.csdn.net/zhangerqing 一、设计模式的分类 总体来说...
    j_cong阅读 2,055评论 0 20
  • 原文链接:http://blog.csdn.net/zhangerqing http://www.cnblogs....
    孤独杂货铺阅读 1,507评论 0 3
  • 一、设计模式的分类 总体来说设计模式分为三大类: 创建型模式,共五种:工厂方法模式、抽象工厂模式、单例模式、建造者...
    RamboLI阅读 742评论 0 1
  • 光妹来到我家说:“胖子要出来了。” 我妈没搭话,只央她坐下。 光妹是本庄人。现下儿子已娶了媳妇。两个女儿也都成了人...
    一虫杉_阅读 879评论 0 0
  • 临摹中 没有打灯光 来张打灯光的,嘻嘻(˙︶˙)
    宠就好了阅读 226评论 0 0