先了解一下简单工厂(它不属于GOF23种设计模式):
由一个工厂对象决定创建出哪一种产品类的实例
适用场景:
工厂类负责创建的对象比较少
客户端(应用层)只知道传入工厂类的参数
对于如何创建对象(逻辑)不关心
简单工厂优点
只需要传入一个正确的参数,就可以获取你所需要的对象
而无须知道其创建细节
简单工厂-缺点
工厂类的职责相对过重,增加新的产品
需要修改工厂类的判断逻辑,违背开闭原则
SimpleFactoryPattern
package com.gxh.simpleFactoryPattern;
/**
* ClassName : Product
* Package : com.gxh.simpleFactoryPattern
* Description :
* 抽象产品
* @author : guxiaohao
* contact me : 2896431151@qq.com
* @date : 2021/6/17 0017 - 19:08
*/
public interface Product {
void show();
}
package com.gxh.simpleFactoryPattern;
/**
* ClassName : ConcreteProduct1
* Package : com.gxh.simpleFactoryPattern
* Description :
* 产品1
* @author : guxiaohao
* contact me : 2896431151@qq.com
* @date : 2021/6/17 0017 - 19:10
*/
public class ConcreteProduct1 implements Product {
@Override
public void show() {
System.out.println("具体产品1.....");
}
}
package com.gxh.simpleFactoryPattern;
/**
* ClassName : ConcreteProduct2
* Package : com.gxh.simpleFactoryPattern
* Description :
*
* @author : guxiaohao
* contact me : 2896431151@qq.com
* @date : 2021/6/17 0017 - 19:12
*/
public class ConcreteProduct2 implements Product {
@Override
public void show() {
System.out.println("具体产品2.....");
}
}
package com.gxh.simpleFactoryPattern;
import com.gxh.factoryMethod.ConcreteProduct1;
import com.gxh.factoryMethod.ConcreteProduct2;
/**
* ClassName : SimpleFactory
* Package : com.gxh.simpleFactoryPattern
* Description :
*
* @author : guxiaohao
* contact me : 2896431151@qq.com
* @date : 2021/6/17 0017 - 19:19
*/
public class SimpleFactory {
public static Product makeProduct(String name) {
if (name.equalsIgnoreCase("ConcreteProduct1")) {
return (Product) new ConcreteProduct1();
} else if (name.equalsIgnoreCase("ConcreteProduct2")) {
return (Product) new ConcreteProduct2();
}
return null;
}
}
package com.gxh.simpleFactoryPattern;
/**
* ClassName : Client
* Package : com.gxh.simpleFactoryPattern
* Description :
*
* @author : guxiaohao
* contact me : 2896431151@qq.com
* @date : 2021/6/17 0017 - 19:15
*/
public class Client {
public static void main(String[] args) {
Product product1 = SimpleFactory.makeProduct("ConcreteProduct1");
product1.show();
Product product2 = SimpleFactory.makeProduct("ConcreteProduct2");
product2.show();
}
}
工厂方法模式
定义:定义一个创建对象的接口
但让实现这个接口的类来决定实例化哪个类
工厂方法让类的实例化推迟到子类中进行
工厂方法-适用场景
◆创建对象需要大量重复的代码
◆客户端(应用层)不依赖于产品如何被创建、实现等细节
◆一个类通过其子类来指定创建哪个对象
工厂方法优点
用户只需要关心所需产品对应的工厂,无须关心创建细节
◆加入新产品符合开闭原则,提高可扩展性
工厂方法-缺点
◆类的个数容易过多,增加复杂度
◆增加了系统的抽象性和理解难度
package com.gxh.factoryMethod;
/**
* ClassName : Product
* Package : com.gxh.factoryMethod
* Description :
* 抽象产品:提供了产品的接口
* @author : guxiaohao
* contact me : 2896431151@qq.com
* @date : 2021/6/17 0017 - 19:32
*/
public interface Product {
public void show();
}
package com.gxh.factoryMethod;
/**
* ClassName : ConcreteProduct1
* Package : com.gxh.simpleFactoryPattern
* Description :
* 产品1
* @author : guxiaohao
* contact me : 2896431151@qq.com
* @date : 2021/6/17 0017 - 19:10
*/
public class ConcreteProduct1 implements Product {
@Override
public void show() {
System.out.println("具体产品1.....");
}
}
package com.gxh.factoryMethod;
/**
* ClassName : ConcreteProduct2
* Package : com.gxh.simpleFactoryPattern
* Description :
*
* @author : guxiaohao
* contact me : 2896431151@qq.com
* @date : 2021/6/17 0017 - 19:12
*/
public class ConcreteProduct2 implements Product {
@Override
public void show() {
System.out.println("具体产品2.....");
}
}
package com.gxh.factoryMethod;
/**
* ClassName : AbstractFactory
* Package : com.gxh.factoryMethod
* Description :
* 抽象工厂:提供了产品的生成方法
* @author : guxiaohao
* contact me : 2896431151@qq.com
* @date : 2021/6/17 0017 - 19:34
*/
public interface AbstractFactory {
public Product newProduct();
}
package com.gxh.factoryMethod;
/**
* ClassName : ConcreteFactory2
* Package : com.gxh.factoryMethod
* Description :
* 具体工厂1:实现了厂品的生成方法
* @author : guxiaohao
* contact me : 2896431151@qq.com
* @date : 2021/6/17 0017 - 19:37
*/
public class ConcreteFactory1 implements AbstractFactory {
@Override
public Product newProduct() {
System.out.println("具体工厂1生成-->具体产品1...");
return (Product) new ConcreteProduct1();
}
}
package com.gxh.factoryMethod;
/**
* ClassName : ConcreteFactory2
* Package : com.gxh.factoryMethod
* Description :
* 具体工厂2:实现了厂品的生成方法
* @author : guxiaohao
* contact me : 2896431151@qq.com
* @date : 2021/6/17 0017 - 19:37
*/
public class ConcreteFactory2 implements AbstractFactory {
@Override
public Product newProduct() {
System.out.println("具体工厂2生成-->具体产品2...");
return (Product) new ConcreteProduct2();
}
}
package com.gxh.factoryMethod;
/**
* ClassName : Client
* Package : com.gxh.factoryMethod
* Description :
*
* @author : guxiaohao
* contact me : 2896431151@qq.com
* @date : 2021/6/17 0017 - 19:40
*/
public class Client {
public static void main(String[] args) {
AbstractFactory abstractFactory1 = new ConcreteFactory1();
abstractFactory1.newProduct();
AbstractFactory abstractFactory2 = new ConcreteFactory2();
abstractFactory2.newProduct();
}
}
抽象工厂模式
◆定义:抽象工厂模式提供一个创建一系列相关或相互依赖对象的接口
◆无须指定它们具体的类
抽象工厂-适用场景
客户端(应用层)不依赖于产品类实例如何被创建、实现等细节
强调一系列相关的产品对象(属于同一产品族)一起使用创建对
象需要大量重复的代码
提供一个产品类的库,所有的产品以同样的接口出现,
从而使客户端不依赖于具体实现
抽象工厂优点
◆具体产品在应用层代码隔离,无须关心创建细节
◆将一个系列的产品族统一到一起创建
抽象工厂-缺点
规定了所有可能被创建的产品集合,产品族中扩展新的产品困难,
需要修改抽象工厂的接口
◆增加了系统的抽象性和理解难度
package com.gxh.abstractFactory;
/**
* ClassName : Product
* Package : com.gxh.factoryMethod
* Description :
* 抽象产品:提供了产品的接口
* @author : guxiaohao
* contact me : 2896431151@qq.com
* @date : 2021/6/17 0017 - 19:32
*/
public interface Product1 {
public void show1();
}
package com.gxh.abstractFactory;
/**
* ClassName : Product2
* Package : com.gxh.abstractFactory
* Description :
*
* @author : guxiaohao
* contact me : 2896431151@qq.com
* @date : 2021/6/17 0017 - 20:14
*/
public interface Product2 {
public void show2();
}
package com.gxh.abstractFactory;
/**
* ClassName : ConcreteProduct1
* Package : com.gxh.simpleFactoryPattern
* Description :
* 产品1
* @author : guxiaohao
* contact me : 2896431151@qq.com
* @date : 2021/6/17 0017 - 19:10
*/
public class ConcreteProduct1 implements Product1 {
@Override
public void show1() {
System.out.println("具体产品1.....");
}
}
package com.gxh.abstractFactory;
/**
* ClassName : ConcreteProduct2
* Package : com.gxh.simpleFactoryPattern
* Description :
*
* @author : guxiaohao
* contact me : 2896431151@qq.com
* @date : 2021/6/17 0017 - 19:12
*/
public class ConcreteProduct2 implements Product2 {
@Override
public void show2() {
System.out.println("具体产品2.....");
}
}
package com.gxh.abstractFactory;
/**
* ClassName : AbstractFactory
* Package : com.gxh.factoryMethod
* Description :
* 抽象工厂:提供了产品的生成方法
* @author : guxiaohao
* contact me : 2896431151@qq.com
* @date : 2021/6/17 0017 - 19:34
*/
public interface AbstractFactory {
public Product1 newProduct1();
public Product2 newProduct2();
}
package com.gxh.abstractFactory;
/**
* ClassName : ConcreteFactory2
* Package : com.gxh.factoryMethod
* Description :
* 具体工厂1:实现了厂品的生成方法
* @author : guxiaohao
* contact me : 2896431151@qq.com
* @date : 2021/6/17 0017 - 19:37
*/
public class ConcreteFactory1 implements AbstractFactory {
@Override
public Product1 newProduct1() {
System.out.println("具体工厂1生成-->具体产品11...");
return (Product1) new ConcreteProduct1();
}
@Override
public Product2 newProduct2() {
System.out.println("具体工厂1生成-->具体产品12...");
return (Product2) new ConcreteProduct2();
}
}
package com.gxh.abstractFactory;
/**
* ClassName : ConcreteFactory2
* Package : com.gxh.factoryMethod
* Description :
* 具体工厂2:实现了厂品的生成方法
* @author : guxiaohao
* contact me : 2896431151@qq.com
* @date : 2021/6/17 0017 - 19:37
*/
public class ConcreteFactory2 implements AbstractFactory {
@Override
public Product1 newProduct1() {
System.out.println("具体工厂2生成-->具体产品21...");
return (Product1) new ConcreteProduct1();
}
@Override
public Product2 newProduct2() {
System.out.println("具体工厂2生成-->具体产品22...");
return (Product2) new ConcreteProduct2();
}
}
package com.gxh.abstractFactory;
/**
* ClassName : Client
* Package : com.gxh.factoryMethod
* Description :
*
* @author : guxiaohao
* contact me : 2896431151@qq.com
* @date : 2021/6/17 0017 - 19:40
*/
public class Client {
public static void main(String[] args) {
AbstractFactory abstractFactory1 = new ConcreteFactory1();
abstractFactory1.newProduct1();
abstractFactory1.newProduct2();
AbstractFactory abstractFactory2 = new ConcreteFactory2();
abstractFactory2.newProduct1();
abstractFactory2.newProduct2();
}
}
建造者模式
定义:指将一个复杂对象的构造与它的表示分离,使同样的构建过程可以创建不同的表示,这样的设计模式被称为建造者模式。
它是将一个复杂的对象分解为多个简单的对象,然后一步一步构建而成。它将变与不变相分离,即产品的组成部分是不变的,但每一部分是可以灵活选择的。
优点:
封装性好,构建和表示分离。
扩展性好,各个具体的建造者相互独立,有利于系统的解耦。
客户端不必知道产品内部组成的细节,建造者可以对创建过程逐步细化,而不对其它模块产生任何影响,便于控制细节风险。
缺点:
产品的组成部分必须相同,这限制了其使用范围。
如果产品的内部变化复杂,如果产品内部发生变化,则建造者也要同步修改,后期维护成本较大。
建造者(Builder)模式和工厂模式的关注点不同:建造者模式注重零部件的组装过程,而工厂方法模式更注重零部件的创建过程,但两者可以结合使用。
Builderpackage com.gxh.builder;
/**
* ClassName : Builder
* Package : com.gxh.builder
* Description :
* 产品角色(Product):它是包含多个组成部件的复杂对象,由具体建造者来创建其各个零部件。
* @author : guxiaohao
* contact me : 2896431151@qq.com
* @date : 2021/6/17 0017 - 20:38
*/
public class Product {
private String partA;
private String partB;
private String partC;
public void setPartA(String partA) {
this.partA = partA;
}
public void setPartB(String partB) {
this.partB = partB;
}
public void setPartC(String partC) {
this.partC = partC;
}
public void show() {
//显示产品的特性
System.out.println("产品建造完成");
}
}
package com.gxh.builder;
/**
* ClassName : Builder
* Package : com.gxh.builder
* Description :
* (2) 抽象建造者:包含创建产品各个子部件的抽象方法
* @author : guxiaohao
* contact me : 2896431151@qq.com
* @date : 2021/6/17 0017 - 20:40
*/
public abstract class Builder {
//创建产品对象
protected Product product = new Product();
public abstract void buildPartA();
public abstract void buildPartB();
public abstract void buildPartC();
//返回产品对象
public Product getResult() {
return product;
}
}
package com.gxh.builder;
/**
* ClassName : ConcreteBuilder
* Package : com.gxh.builder
* Description :
* (3) 具体建造者:实现了抽象建造者接口。
* @author : guxiaohao
* contact me : 2896431151@qq.com
* @date : 2021/6/17 0017 - 20:43
*/
public class ConcreteBuilder extends Builder {
@Override
public void buildPartA() {
product.setPartA("建造 PartA");
}
@Override
public void buildPartB() {
product.setPartA("建造 PartB");
}
@Override
public void buildPartC() {
product.setPartA("建造 PartC");
}
}
package com.gxh.builder;
/**
* ClassName : Director
* Package : com.gxh.builder
* Description :
* (4) 指挥者:调用建造者中的方法完成复杂对象的创建。
* @author : guxiaohao
* contact me : 2896431151@qq.com
* @date : 2021/6/17 0017 - 20:46
*/
public class Director {
private Builder builder;
public Director(Builder builder) {
this.builder = builder;
}
//产品构建与组装方法
public Product construct() {
builder.buildPartA();
builder.buildPartB();
builder.buildPartC();
return builder.getResult();
}
}
package com.gxh.builder;
/**
* ClassName : Client
* Package : com.gxh.builder
* Description :
*
* @author : guxiaohao
* contact me : 2896431151@qq.com
* @date : 2021/6/17 0017 - 20:48
*/
public class Client {
public static void main(String[] args) {
Builder builder = new ConcreteBuilder();
Director director = new Director(builder);
Product product = director.construct();
product.show();
}
}
单例模式
为了节省内存资源、保证数据内容的一致性,对某些类要求只能创建一个实例,这就是所谓的单例模式。
定义:指一个类只有一个实例,且该类能自行创建这个实例的一种模式。例如,Windows 中只能打开一个任务管理器,这样可以避免因打开多个任务管理器窗口而造成内存资源的浪费,或出现各个窗口显示内容的不一致等错误。
在计算机系统中,还有 Windows 的回收站、操作系统中的文件系统、多线程中的线程池、显卡的驱动程序对象、打印机的后台处理服务、应用程序的日志对象、数据库的连接池、网站的计数器、Web 应用的配置对象、应用程序中的对话框、系统中的缓存等常常被设计成单例。
单例模式在现实生活中的应用也非常广泛,例如公司 CEO、部门经理等都属于单例模型。J2EE 标准中的 ServletContext 和 ServletContextConfig、Spring 框架应用中的 ApplicationContext、数据库中的连接池等也都是单例模式。
单例模式有 3 个特点:
单例类只有一个实例对象;
该单例对象必须由单例类自行创建;
单例类对外提供一个访问该单例的全局访问点。
单例模式的优点:
单例模式可以保证内存里只有一个实例,减少了内存的开销。
可以避免对资源的多重占用。
单例模式设置全局访问点,可以优化和共享资源的访问。
单例模式的缺点:
单例模式一般没有接口,扩展困难。如果要扩展,则除了修改原来的代码,没有第二种途径,违背开闭原则。
在并发测试中,单例模式不利于代码调试。在调试过程中,如果单例中的代码没有执行完,也不能模拟生成一个新的对象。
单例模式的功能代码通常写在一个类中,如果功能设计不合理,则很容易违背单一职责原则。
单例模式的应用场景
对于 Java 来说,单例模式可以保证在一个 JVM 中只存在单一实例。单例模式的应用场景主要有以下几个方面。
需要频繁创建的一些类,使用单例可以降低系统的内存压力,减少 GC。
某类只要求生成一个对象的时候,如一个班中的班长、每个人的身份证号等。
某些类创建实例时占用资源较多,或实例化耗时较长,且经常使用。
某类需要频繁实例化,而创建的对象又频繁被销毁的时候,如多线程的线程池、网络连接池等。
频繁访问数据库或文件的对象。
对于一些控制硬件级别的操作,或者从系统上来讲应当是单一控制逻辑的操作,如果有多个实例,则系统会完全乱套。
当对象需要被共享的场合。由于单例模式只允许创建一个对象,共享该对象可以节省内存,并加快对象访问速度。如 Web 中的配置对象、数据库的连接池等。
单例模式的结构与实现
单例模式是设计模式中最简单的模式之一。通常,普通类的构造函数是公有的,外部类可以通过“new 构造函数()”来生成多个实例。但是,如果将类的构造函数设为私有的,外部类就无法调用该构造函数,也就无法生成多个实例。这时该类自身必须定义一个静态私有实例,并向外提供一个静态的公有函数用于创建或获取该静态私有实例
第 1 种:懒汉式单例
package com.gxh.singleton;
/**
* ClassName : LazySingleton
* Package : com.gxh.singleton
* Description :
* 第 1 种:懒汉式单例
* 该模式的特点是类加载时没有生成单例,只有当第一次调用 getlnstance 方法时才去创建这个单例
* 如果编写的是多线程程序,则不要删除上例代码中的关键字 volatile 和 synchronized,否则将存在线程非安全的问题。
* 如果不删除这两个关键字就能保证线程安全,但是每次访问时都要同步,会影响性能,且消耗更多的资源,这是懒汉式单例的缺点。
* @author : guxiaohao
* contact me : 2896431151@qq.com
* @date : 2021/6/17 0017 - 22:29
*/
public class LazySingleton {
//保证 instance 在所有线程中同步
private static volatile LazySingleton instance = null;
private LazySingleton () {}//private 避免类在外部被实例化
public static synchronized LazySingleton getInstance() {
//getInstance 方法前加同步
if (instance == null) {
instance = new LazySingleton();
}
return instance;
}
}
第 2 种:饿汉式单例
package com.gxh.singleton;
/**
* ClassName : HungrySingleton
* Package : com.gxh.singleton
* Description :
* 第 2 种:饿汉式单例
* 该模式的特点是类一旦加载就创建一个单例,保证在调用 getInstance 方法之前单例已经存在了。
* 饿汉式单例在类创建的同时就已经创建好一个静态的对象供系统使用,以后不再改变,所以是线程安全的,可以直接用于多线程而不会出现问题。
* @author : guxiaohao
* contact me : 2896431151@qq.com
* @date : 2021/6/17 0017 - 22:40
*/
public class HungrySingleton {
private static final HungrySingleton instance = new HungrySingleton();
private HungrySingleton() {}//private 避免类在外部被实例化
public static HungrySingleton getInstance() {
return instance;
}
}
原型模式
定义如下:用一个已经创建的实例作为原型,通过复制该原型对象来创建一个和原型相同或相似的新对象。在这里,原型实例指定了要创建的对象的种类。用这种方式创建对象非常高效,根本无须知道对象创建的细节。例如,Windows 操作系统的安装通常较耗时,如果复制就快了很多。在生活中复制的例子非常多,这里不一一列举了。
原型模式的优点:
Java 自带的原型模式基于内存二进制流的复制,在性能上比直接 new 一个对象更加优良。
可以使用深克隆方式保存对象的状态,使用原型模式将对象复制一份,并将其状态保存起来,简化了创建对象的过程,以便在需要的时候使用(例如恢复到历史某一状态),可辅助实现撤销操作。
原型模式的缺点:
需要为每一个类都配置一个 clone 方法
clone 方法位于类的内部,当对已有类进行改造的时候,需要修改代码,违背了开闭原则。
当实现深克隆时,需要编写较为复杂的代码,而且当对象之间存在多重嵌套引用时,为了实现深克隆,每一层对象对应的类都必须支持深克隆,实现起来会比较麻烦。因此,深克隆、浅克隆需要运用得当。
由于 Java 提供了对象的 clone() 方法,所以用 Java 实现原型模式很简单。
prototypepackage com.gxh.prototype;
/**
* ClassName : Mail
* Package : com.gxh.prototype
* Description :
*
* @author : guxiaohao
* contact me : 2896431151@qq.com
* @date : 2021/6/17 0017 - 23:01
*/
public class Mail implements Cloneable{
private String name;
private String emailAddress;
private String content;
public Mail () {
System.out.println("Mail class Constructor");
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getEmailAddress() {
return emailAddress;
}
public void setEmailAddress(String emailAddress) {
this.emailAddress = emailAddress;
}
public String getContent() {
return content;
}
public void setContent(String content) {
this.content = content;
}
@Override
public String toString() {
return "Mail{" +
"name='" + name + '\'' +
", emailAddress='" + emailAddress + '\'' +
", content='" + content + '\'' +
'}'+ super.toString();
}
@Override
protected Object clone() throws CloneNotSupportedException {
System.out.println("clone mail object ");
return super.clone();
}
}
package com.gxh.prototype;
import java.text.MessageFormat;
/**
* ClassName : MailUtil
* Package : com.gxh.prototype
* Description :
*
* @author : guxiaohao
* contact me : 2896431151@qq.com
* @date : 2021/6/17 0017 - 23:08
*/
public class MailUtil {
public static void sendMail (Mail mail) {
String outputContent = "向{0},邮件地址:{1},邮件内容:{2}发送成功";
System.out.println(MessageFormat.format(outputContent, mail.getName(), mail.getEmailAddress(), mail.getContent()));
}
public static void saveOriginMailRecord(Mail mail) {
System.out.println("存储originMail记录, originMail:" + mail.getContent());
}
}
package com.gxh.prototype;
/**
* ClassName : Test
* Package : com.gxh.prototype
* Description :
*
* @author : guxiaohao
* contact me : 2896431151@qq.com
* @date : 2021/6/17 0017 - 23:14
*/
public class Test {
public static void main(String[] args) throws CloneNotSupportedException {
Mail mail = new Mail();
mail.setContent("初始化的模板");
System.out.println("初始化mail:"+mail);
for (int i = 0; i < 10; i++) {
Mail mailTemp = (Mail) mail.clone();//克隆的时候,没有调用mail的构造方法
mailTemp.setName("姓名" + i);
mailTemp.setEmailAddress("姓名" + i + "@qq.com");
mailTemp.setContent("恭喜你,中奖了");
MailUtil.sendMail(mailTemp);
System.out.println("克隆的mailTemp:"+mailTemp);
}
MailUtil.saveOriginMailRecord(mail);
}
}
运行结果
网友评论