【设计模式①】单例、原型、工厂方法、抽象工厂模式
环境
Java:1.8.0_202-b08
dependency:
- lombok 1.18.6
- Guava 27.0.1-jre
- slf4j-log4j12 1.7.25
Github Repositories: https://github.com/ilssio/design-pattern
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();
}
}
参考文章
- http://c.biancheng.net/view/1343.html
- https://baike.baidu.com/item/%E5%8E%9F%E5%9E%8B%E6%A8%A1%E5%BC%8F/4941014?fr=aladdin
- https://www.cnblogs.com/zhaoyan001/p/6365064.html
- http://www.cnblogs.com/garryfu/p/7976546.html
- http://c.biancheng.net/view/1348.html
- 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
- http://www.cnblogs.com/forlina/archive/2011/06/21/2086114.html
- https://baike.baidu.com/item/%E6%8A%BD%E8%B1%A1%E5%B7%A5%E5%8E%82%E6%A8%A1%E5%BC%8F
- http://c.biancheng.net/view/1351.html
- https://www.jianshu.com/p/7deb64f902db