设计模式-创建型设计模式
简单工厂模式
- 定义
由一个工厂对象决定创建出哪一种产品类的实例 - 适用场景
工厂类负责创建的对象比较少
客户端(应用层)只知道传入工厂类的参数,并不关心创建对象的逻辑 - 优点
只需要传入一个正确的参数,就可以获取所需要的对象,而不需要关心创建对象的细节 - 缺点
工厂类的职责相对过重,增加新的产品,需要修改工厂类的判断逻辑,违背了开闭原则
public abstract class BaseText {
public abstract void createText();
}
-------------------------------------
public class HtmlText extends BaseText{
@Override
public void createText() {
System.out.println("生成HTML文本");
}
}
-------------------------------------
public class JsonText extends BaseText {
@Override
public void createText() {
System.out.println("生成JSON文本");
}
}
--------------------------------------
public class TextFactory extends JsonText {
/*这种方法不好扩展
public BaseText getText(String type){
if ("html".equalsIgnoreCase(type)){
return new HtmlText();
}else if("json".equalsIgnoreCase(type)){
return new JsonText();
}
return null;
}*/
/**
* 通过反射实现简单工厂--符合开闭原则
* @param c 类
* @return
*/
public BaseText getText(Class c){
BaseText baseText = null;
try {
baseText = (BaseText) Class.forName(c.getName()).newInstance();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
return baseText;
}
}
------------------------------------------
public class Demo {
public static void main(String[] args) {
TextFactory textFactory = new TextFactory();
//BaseText text = textFactory.getText("html");
BaseText text = textFactory.getText(JsonText.class);
if (text==null){
return;
}
text.createText();
}
}
工厂方法模式
-
定义
定义一个创建对象的接口,但让实现这个接口的类来决定实例化哪个类,工厂方法让类的实例化推迟到子类中进行 -
适用场景
创建对象需要大量重复代码
客户端(应用层)不依赖与产品类实例如何被创建等细节
一个类通过其子类来指定创建哪个对象 -
优点
用户只需要关注所需产品对应的工厂类,而不需要关心创建细节
加入新产品符合开闭原则,提高可扩展性 -
缺点
类的个数容易过多,增加系统复杂度
增加了系统的抽象性和理解难度
抽象工厂模式
- 定义
抽象工厂模式提供一个创建一系列相关或相互依赖对象的接口无需指定它们具体的类 - 适用场景
客户端(应用层)不依赖与产品类实例如何被创建、实现等细节
强调一系列相关的产品对象(属于同一产品族)一起使用创建对象需要大量重复代码
提供一个产品类的库,所有的产品以同样的接口出现,从而使客户端不依赖于具体实现 - 优点
具体产品在应用层代码隔离,无需关心创建细节
将一个系列的产品族统一到一起创建 - 缺点
规定了所有可能被创建的产品集合,产品族中扩展新的产品困难,需要修改抽象工厂的接口
增加了系统的抽象性和理解难度
白话理解:
产品族:美的冰箱、美的洗衣机、美的空调 都是美的品牌 属于一个产品族
产品等级结构:美的冰箱、海尔冰箱 属于一个产品等级
工厂方法模式针对 产品等级结构/ 抽象工厂模式针对 产品族
建造者模式
-
定义
将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示
用户只需要指定需要建造的类型就可以得到它们,建造过程和细节不需要知道 -
适用场景
如果一个对象有非常复杂的内部结构(很多属性)
想把复杂对象的创建和使用分离 -
优点
封装性好,创建和使用分离
扩展性好,建造类之间独立,一定程度上解耦 -
缺点
产生多余的Builder对象
产品内部发生变化,建造者都要修改,成本较大
public class Goods {
private String name;
private String image;
private String price;
public Goods(GoodsBuilder goodsBuilder){
this.name = goodsBuilder.name;
this.image = goodsBuilder.image;
this.price = goodsBuilder.price;
}
public static class GoodsBuilder{
private String name;
private String image;
private String price;
public GoodsBuilder buildName(String name){
this.name = name;
return this;
}
public GoodsBuilder buildImage(String image){
this.image = image;
return this;
}
public GoodsBuilder buildPrice(String price){
this.price = price;
return this;
}
public Goods build(){
return new Goods(this);
}
}
}
---------------------------------------
public class Test {
public static void main(String[] args) {
Goods goods = new Goods.GoodsBuilder().buildName("手机").buildImage("手机图片").buildPrice("100.00").build();
System.out.println(goods);
}
}
单例模式
- 定义
保证一个类仅有一个实例,并提供一个全局访问点 - 适用场景
想确保任何情况下都绝对只有一个实例 - 优点
在内存中只有一个实例,减少了内存开销
可以避免对资源的多重占用
设置全局访问点,严格控制访问 - 缺点
没有接口,扩展困难 - 重点
私有构造器
线程安全
延迟加载
序列化和反序列化安全
反射
/**
* 懒汉式--线程不安全--注重延迟加载
*/
public class LazySingleton {
private static LazySingleton instance = null;
private LazySingleton(){}
/**
* 加锁使之线程安全-- synchronized在修饰static时锁的是整个类
*/
public synchronized static LazySingleton getInstance(){
if (instance == null){
//多线程执行可能new多次
instance = new LazySingleton();
}
return instance;
}
}
/**
* DoubleCheck双重检查和volatile禁止重排序问题
*/
public class LazyDoubleCheckSingleton {
private volatile static LazyDoubleCheckSingleton instance = null;
private LazyDoubleCheckSingleton(){}
public static LazyDoubleCheckSingleton getInstance(){
if (instance == null){
synchronized (LazyDoubleCheckSingleton.class){
if (instance == null){
instance = new LazyDoubleCheckSingleton();
//重排序问题
//1.分配内存给这个对象
// //3.instance 指向刚分配的内存地址
//2.初始化对象
// intra-thread semantics
// -----//3.instance 指向刚分配的内存地址
}
}
}
return instance;
}
}
// 静态内部类
public class StaticInnerClassSingleton {
private static class InnerClass{
private static StaticInnerClassSingleton instance = new StaticInnerClassSingleton();
}
public static StaticInnerClassSingleton getInstance(){
return InnerClass.instance;
}
private StaticInnerClassSingleton(){}
}
// 饿汉式--线程安全--类加载时完成初始化
public class HungrySingleton {
private final static HungrySingleton instance = new HungrySingleton();
private HungrySingleton(){}
public static HungrySingleton getInstance(){
return instance;
}
}
--------------静态代码块初始化-----------
public class HungrySingleton {
private final static HungrySingleton instance;
static{
//优点-可以执行其他初始化代码
instance = new HungrySingleton();
}
private HungrySingleton(){}
public static HungrySingleton getInstance(){
return instance;
}
}
原型模式
- 定义
指原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象
不需要知道任何创建细节,不调用构造函数 - 适用场景
类初始化消耗较多资源
new产生的一个对象需要非常繁琐的过程(数据准备、访问权限等)
构造函数比较复杂
循环体中生成大量对象时 - 优点
原型模式性能比直接new一个对象性能高
简化创建过程 - 缺点
必须配备克隆方法
对克隆复杂对象或对克隆出的对象进行复杂改造时,容易引入风险
深拷贝、浅拷贝要运用得当 - 扩展
深克隆
浅克隆
/**邮件类实现Cloneable接口
* @author MrPeng
* @date 2019/2/13
*/
public class Mail implements Cloneable{
private String name;
private String address;
private String content;
public Mail(){
System.out.println("Mail创建");
}
/*get/set方法*/
@Override
protected Object clone() throws CloneNotSupportedException {
System.out.println("Mail克隆");
return super.clone();
}
}
---------------------------
/**邮件发送类
* @author MrPeng
* @date 2019/2/13
*/
public class MailUtil {
public static void sendMail(Mail mail){
String outputContent = "{0}同学,地址:{1},内容:{2}发送邮件成功";
System.out.println(MessageFormat.format(outputContent,mail.getName(),mail.getAddress(),mail.getContent()));
}
public static void saveOriginMailRecord(Mail mail){
System.out.println("存储原始记录,originMail:"+mail.getContent());
}
}
-------------------------------
/**原型模式测试
* @author MrPeng
* @date 2019/2/13
*/
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 < 3;i++){
Mail mailTemp = (Mail) mail.clone();
mailTemp.setName("姓名"+i);
mailTemp.setAddress(""+i+"@xx.com");
mailTemp.setContent("你中奖了");
MailUtil.sendMail(mailTemp);
System.out.println("克隆的mailTemp:"+mailTemp);
}
MailUtil.saveOriginMailRecord(mail);
}
}