简介
创建型模式,就是创建对象的模式,抽象了实例化的过程。它帮助一个系统独立于如何创建、组合和表示它的那些对象。关注的是对象的创建,创建型模式将创建对象的过程进行了抽象,也可以理解为将创建对象的过程进行了封装,作为客户程序仅仅需要去使用对象,而不再关心创建对象过程中的逻辑
单例模式
定义:确保一个类只有一个实例,而且自行实例化并向整个系统提供这个实例。
类图:
主要有三个部分:
私有的构造方法
指向自己实例的私有静态引用
以自己实例为返回值的静态的公有的方法
特点:*
优点:
在内存中只有一个对象,节省内存空间。
避免频繁的创建销毁对象,可以提高性能。
避免对共享资源的多重占用。
可以全局访问。
适用场景:
需要频繁实例化然后销毁的对象。
创建对象时耗时过多或者耗资源过多,但又经常用到的对象。
有状态的工具类对象。
频繁访问数据库或文件的对象等等。
注意事项:
只能使用单例类提供的方法得到单例对象,不要使用反射,否则将会实例化一个新对象。
不要做断开单例类对象与类中静态引用的危险操作。
多线程使用单例使用共享资源时,注意线程安全问题。
饿汉式:
/**
* 一:饿汉式(类加载的时候就创建了实例)
* 优点:实现了线程安全,编写简单;执行效率高
* 缺点:初始化就创建了实例,对加载速度和内存有消耗,,所以这种方法要求单例对象初始化速度快且占用内存小
*/
// 1、成员变量静态化
private static Singleton3 instance = new Singleton3();
//2、构造函数私有化,防止外部实例化
private Singleton3(){}
//3、提供公共静态创建实例方法
public static Singleton3 getInstance(){
return instance;
}
/**
* 二:枚举类型:根据枚举类型的特点,实现单例模式所需要的创建单例、线程安全、简洁的需求
* 优点:实现比较简洁,保证了单实例,线程安全
* 缺点:使用枚举类型,不是很熟悉
*/
/**
* 枚举类型的特点:
* 1、枚举类型 = 不可被继承的类(final):
* 枚举本质上是通过普通类实现的,只是编译器为我们进行了特殊处理
* 每个枚举类型都继承自java.lang.Enum,并自动添加了values(),valueOf()
* 枚举类的实例 = 常量
* 2、每个枚举元素 = 类静态常量 = 1个实例
* 枚举元素,都是通过静态代码来进行初始化,即在类加载期间进行初始化,保证了实例只被创建一次,线程安全
* 获取枚举元素 = 获取实例
* 3、构造方法 访问权限 默认=私有(private):他的构造器是私有的,底层没有可供调用的无参数的构造器;防止了其他人创建实例
* 4、每一个枚举类型&枚举变量在JVM中都是唯一的:
* 即java在序列化和反序列化美剧时做了特殊的规定:枚举的writeObject(),readObject(),readObjectNoData()等方法是被禁用的,因此不存在序列化接口之后调用readObject会破环单例的问题
* 保证了枚举元素的不可变行,即不能通过克隆、序列化&反序列化来复制枚举,即保证了1个枚举常量=1个实例 即单例
*/
public enum Singleton {
INSTANCE;
public void whateverMethod() {
}
}
懒汉式:
//程序中创建类只有两种方式:1创建类的一个对象,用该对象去调用类中的方法;2使用类名直接调用类中方法,类名.方法名();单例模式防止外部new对象,只能使用类方法,且是静态的。
/**
* 一:懒汉式(需要的时候创建实例),线程不安全。当多个线程同时访问时,不能正常工作。
* 优点:按需加载
* 缺点:线程不安全。多个线程同时访问时,会创建多个实例。
*/
// 1、成员变量静态化
private static Singleton1 instance;
//2、构造函数私有化,防止外部实例化
private Singleton1(){}
//3、提供公共静态创建实例方法
public static Singleton1 getInstance() {
if (instance == null) {
instance = new Singleton1();
}
return instance;
}
/**
* 二:懒汉式:线程安全,加同步锁,
* 优点:实现了线程安全
* 缺点:每次访问都要进行线程同步(调用synchronized锁),造成过多的同步开销(加锁=耗时、耗能)
*/
// 1、成员变量静态化
private static Singleton1 instance;
//2、构造函数私有化,防止外部实例化
private Singleton1(){}
//3、提供公共静态创建实例方法
public static synchronized Singleton1 getInstance() {
if (instance == null) {
instance = new Singleton1();
}
return instance;
}
// 1、成员变量静态化
private static Singleton1 instance;
//2、构造函数私有化,防止外部实例化
private Singleton1(){}
//3、提供公共静态创建实例方法
public static Singleton1 getInstance() {
synchronized(Singleton.class){
if (instance == null) {
instance = new Singleton1();
}
}
return instance;
}
/**
*三:懒汉式改进—双重校验锁;在同步锁的基础上,添加一层if判断,若单例已经创建,则不需要再执行加锁操作就可以获取实例,从而提高了性能。
*优点:避免了每次调用都要调用synchronized锁,同时双重校验又保证了线程安全,不会重复创建实例。
* 缺点:较为复杂,容易出错
*/
// 1、成员变量静态化
private static Singleton1 instance = null;
//2、构造函数私有化,防止外部实例化
private Singleton1(){}
//3、提供公共静态创建实例方法
public static Singleton1 getInstance() {
if (instance == null) {
synchronized (Singleton1.class) {
if (instance == null) {
instance = new Singleton1();
}
}
}
return instance;
}
/**
* 四:静态内部类。在静态内部类中创建单例,在加载内部类时才会创建单例
* 优点:根据静态内部类的特性,实现了线程安全,按需加载,同时比较简洁
*/
// 1、创建静态内部类
private static class Singleton2{
// 静态类里面创建单例
private static Singleton1 instance = new Singleton1();
}
//2、构造函数私有化,防止外部实例化
private Singleton1(){}
//3、提供公共静态创建实例方法
public static Singleton1 getInstance() {
//调用静态类的实例方法
return Singleton2.instance;
}
/**
* 调用过程说明
* 1、外部调用类的getInstance()方法
* 2、getInstance()方法自动调用内部类的方法,实现初始化
* 3、而该类在装载 & 被初始化时,会初始化他的静态域,从而创建单例
* 4、由于是静态域,因此JVM只会加载一遍,java虚拟机保证了线程安全
* 5、最终实现只创建一个实例。
*/
简单工厂模式
定义:又静态工厂模式,可以根据参数的不同返回不同类的实例。
类图:
由此可以看出:简单工厂模式由三部分组成:具体工厂、具体产品和抽象产品
工厂类(Creator)角色:担任这个角色的是简单工厂模式的核心,含有与应用紧密相关的商业逻辑。工厂类在客户端的直接调用下创建产品对象,它往往由一个具体Java类实现。
抽象产品(AbstractProduct)角色:担任这个角色的类是由简单工厂模式所创建的对象的父类,或它们共同拥有的接口。抽象产品角色可以用一个Java接口或者Java抽象类实现。
具体产品(ConcreteProduct)角色:简单工厂模式所创建的任何对象都是这个角色的实例,具体产品角色由一个具体Java类实现。
总结:
简单工厂只有一个工厂类,通过switch语句来区分创建哪个产品。
工厂方法模式是扩展了简单工厂模式,区分为抽象工厂和具体工厂实现。
工厂方法模式
定义:定义一个创建对象的工厂接口,让子类决定实例化哪一个类,将实际的创建工作推迟到子类当中。
类图:
工厂方法模式包含
抽象产品:一般是产品接口或者抽象产品类。主要目的是定义产品的规范,所有的产品实现都必须遵循产品接口定义的规范。产品接口是调用者最为关心的,产品接口定义的优劣直接决定了调用者代码的稳定性。
具体产品:实现产品接口的具体类,决定了产品在客户端中的具体行为。
抽象工厂:一般是工厂接口或者抽象工厂类。是工厂方法模式的核心,与调用者直接交互用来提供产品。
具体工厂:在编程中,工厂实现决定如何实例化产品,是实现扩展的途径,需要有多少种产品,就需要有多少个具体的工厂实现。
优缺点:
优点:(1)封装了创建产品的方法,用户无须关心具体实现;(2)添加新产品时,只需要添加具体产品类和具体工厂类(实现或继承抽象产品、工厂类);(3)将创建工厂方法推迟到子类当中,实现了多态。工厂方法模式也叫多态工厂模式,之所以是多态,因为所有具体工厂类都具有同一父类。
缺点:(1)在添加新产品时,需要添加具体产品类、具体工厂类。当存在较多产品时,导致产品、产品工厂类增多,一定程度上增加了系统的复杂度,更多的类需要编译和运行,给系统带来了一些额外的开销。(2) 由于考虑到系统的可扩展性,需要引入抽象层,在客户端代码中均使用抽象层进行定义,增加了系统的抽象性和理解难度,且在实现时可能需要用到DOM、反射等技术,增加了系统的实现难度。
代码举例
//1、抽象产品类
public interface Moveable {
public void run();
}
//2、具体产品实现类
public class Car implements Moveable {
@Override
public void run() {
System.out.println("小汽车!");
}
}
public class Plane implements Moveable {
@Override
public void run() {
System.out.println("大飞机!");
}
}
//3、抽象工厂类
public abstract class Factory {
public abstract Moveable create();
}
//4、具体工厂实现类
public class CarFactory extends Factory {
@Override
public Moveable create() {
return new Car();
}
}
public class PlaneFactory extends Factory {
@Override
public Moveable create() {
return new Plane();
}
}
//测试类
public class FactoryTest {
@Test
public void FactoryTest(){
Factory car = new CarFactory();
Moveable m = car.create();
// Factory plane = new PlaneFactory();
// Moveable m= plane.create();
m.run();
}
}
抽象工厂模式
定义:提供一个创建一系列相关或相互依赖对象的接口,而无需指定它们具体的类。
类图:
可以看到,抽象工厂模式也是包含抽象产品、具体产品、抽象工厂、具体工厂。
但是抽象工厂中有产品等级结构和产品族的概念。
产品等级结构:产品等级结构即产品的继承结构,如一个抽象类是电视机,其子类有海尔电视机、海信电视机、TCL电视机,则抽象电视机与具体品牌的电视机之间构成了一个产品等级结构,抽象电视机是父类,而具体品牌的电视机是其子类。
产品族:在抽象工厂模式中,产品族是指由同一个工厂生产的,位于不同产品等级结构中的一组产品,如海尔电器工厂生产的海尔电视机、海尔电冰箱,海尔电视机位于电视机产品等级结构中,海尔电冰箱位于电冰箱产品等级结构中。
和工厂方法模式的区别:
工厂方法模式提供的是一个产品等级结构的实现,抽象工厂模式提供多个不同的产品等级结构的实现。
优缺点:
优点:可以在类的内部对产品族进行约束
缺点:产品族扩展比较麻烦。当增加新的产品时,所有的工厂类都要添加其相关代码。
代码举例:
//1、抽象产品类
public abstract class Vehicle{
public abstract void run();
}
public abstract class Food {
public abstract void printName();
}
public abstract class Weapon {
public abstract void shoot();
}
//2、具体实现类
//第一个产品族
public class Car extends Vehicle {
@Override
public void run() {
System.out.println("小汽车!");
}
}
public class Apple extends Food{
@Override
public void printName() {
System.out.println("红苹果");
}
}
public class AK47 extends Weapon {
@Override
public void shoot() {
System.out.println("大火球,huhuhu。。。。。。");
}
}
//第2个产品族
public class Plane extends Vehicle {
@Override
public void run() {
System.out.println("大灰机");
}
}
public class Pizza extends Food{
@Override
public void printName() {
System.out.println("披萨");
}
}
public class _98K extends Weapon{
@Override
public void shoot() {
System.out.println("砰砰砰。。。。。。");
}
}
//3、抽象工厂类
public abstract class AbstractFactory {
public abstract Vehicle createVehicle();
public abstract Weapon createWeapon();
public abstract Food createFood();
}
//4、具体工厂实现类
public class DefaultFactory extends AbstractFactory{
@Override
public Vehicle createVehicle() {
return new Car();
}
@Override
public Weapon createWeapon() {
return new AK47();
}
@Override
public Food createFood() {
return new Apple();
}
}
public class SuperFactory extends AbstractFactory{
@Override
public Vehicle createVehicle() {
return new Plane();
}
@Override
public Weapon createWeapon() {
return new _98K();
}
@Override
public Food createFood() {
return new Pizza();
}
}
//5、测试类
public class AbstractFactoryTest {
@Test
public void abstractFactoryTest(){
// AbstractFactory a = new DefaultFactory();
AbstractFactory a = new SuperFactory();
Vehicle v= a.createVehicle();
v.run();
Weapon w = a.createWeapon();
w.shoot();
Food f= a.createFood();
f.printName();
}
}
总结:
建造者模式
定义:将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。
类图:
建造者模式包含四个要素:
产品类:一般是一个较为复杂的对象,也就是说创建对象的过程比较复杂,一般会有比较多的代码量。在本类图中,产品类是一个具体的类,而非抽象类。实际编程中,产品类可以是由一个抽象类与它的不同实现组成,也可以是由多个抽象类与他们的实现组成。
抽象建造者:引入抽象建造者的目的,是为了将建造的具体过程交与它的子类来实现。这样更容易扩展。一般至少会有两个抽象方法,一个用来建造产品,一个是用来返回产品。
建造者:实现抽象类的所有未实现的方法,具体来说一般是两项任务:组建产品;返回组建好的产品。
导演类:负责调用适当的建造者来组建产品,导演类一般不与产品类发生依赖关系,与导演类直接交互的是建造者类。一般来说,导演类被用来封装程序中易变的部分。
优缺点:
优点:
将具体的业务逻辑实现封装在了导演类中,无须知道具体产品类的结构;
当添加新的产品时,只需要实现一个新的建造者类,并添加相应的导演类实现创建具体的产品。
代码实现:
class Product {
private String name;
private String type;
public void showProduct(){
System.out.println("名称:"+name);
System.out.println("型号:"+type);
}
public void setName(String name) {
this.name = name;
}
public void setType(String type) {
this.type = type;
}
}
abstract class Builder {
public abstract void setPart(String arg1, String arg2);
public abstract Product getProduct();
}
class ConcreteBuilder extends Builder {
private Product product = new Product();
public Product getProduct() {
return product;
}
public void setPart(String arg1, String arg2) {
product.setName(arg1);
product.setType(arg2);
}
}
public class Director {
private Builder builder = new ConcreteBuilder();
public Product getAProduct(){
builder.setPart("宝马汽车","X7");
return builder.getProduct();
}
public Product getBProduct(){
builder.setPart("奥迪汽车","Q5");
return builder.getProduct();
}
}
public class Client {
public static void main(String[] args){
Director director = new Director();
Product product1 = director.getAProduct();
product1.showProduct();
Product product2 = director.getBProduct();
product2.showProduct();
}
}
与工厂模式的区别:
从结构上看,建造者模式只比工厂模式多了一个“导演类”的角色,如果没有这个导演类,就类似简单工厂模式了。
工厂模式是将对象的创建过程封装在工厂类中,由工厂类向客户端提供最终的产品。
建造者模式中,建造类一般只提供产品类中各个组件的建造,而将具体的建造过程交由导演类,由导演类实现具体的产品。
所以建造者模式一般用来创建更复杂的对象。
原型模式
待续。
参考资料
http://design-patterns.readth...
https://www.w3cschool.cn/java...
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。