23种设计模式
1、了解设计模式
- 设计模式 是前辈们对代码开发经验的总结, 是解决特定问题的一系列套路, 他不是语法规定, 而是一套用来提高代码可复用性、可维护性、可读性、稳健性以及安全性的解决方案
- 1995年,GoF合作出版了《设计模式:可复用面向对象软件的基础》一书,共收录了23种设计模式,从此树立了软件设计模式领域的里程碑,人称GoF设计模式
学习设计模式的意义
- 设计模式的本质是面向对象设计原则的实际运用, 是对类的封装性, 继承性和多态性以及类的关联关系和组合关系的充分理解
- 正确使用设计模式具有以下优点:
- 可以提高程序员的思维能力, 编程能力和设计能力
- 使程序设计更加标准化, 代码编制更加工程化, 使软件开发效率大大提高, 从而缩短 软件的开发周期
- 使设计的代码可重用性高, 可读性强, 可靠性高, 灵活性好, 可维护性强
2、GoF 23
- Gof23
- 一种思维, 一种态度, 一种进步
- 创建型模式:
- 单例模式, 工厂模式, 抽象工厂模式, 建造者模式, 原型模式
- 结构型模式:
- 适配器模式, 桥接模式, 装饰模式, 组合模式, 外观模式, 享元模式, 代理模式
- 行为型模式:
- 模板方法模式, 命令模式, 迭代器模式, 观察者模式, 中介者模式, 备忘录模式, 解释器模式, 状态模式, 策略模式, 职责链模式, 访问者模式
3、OOP 七大原则
- 开闭原则: 对扩展开放, 对修改关闭
- 里氏替换原则: 继承必须确保超类所拥有的性质在子类中仍然成立
- 依赖倒置原则: 要面向接口编程, 不要面向实现编程
- 职责原则: 控制类的粒度大小, 将对象解耦, 提高其内聚性
- 接口隔离原则: 要为各个类建立它们需要的专用接口
- 迪米特法则: 只与你的直接朋友交谈,不跟"陌生人"说话
- 合成复用原则: 尽量先使用组合或者聚合等关联关系实现,其次才考虑使用继承关系来实现
4、单例模式
饿汉式、DCL懒汉式,深究
饿汉式
//饿汉式单例
public class Hungry {
//可能会很费空间
private byte[] data1 = new byte[1024*1024];
private byte[] data2 = new byte[1024*1024];
private byte[] data3 = new byte[1024*1024];
private byte[] data4 = new byte[1024*1024];
private Hungry(){
}
private final static Hungry HUNGRY= new Hungry();
public static Hungry getInstance(){
return HUNGRY;
}
}
懒汉式
存在多线程并发模式,后面的DCL懒汉式解决并发问题
public class LazyMan {
private LazyMan(){
System.out.println(Thread.currentThread().getName()+"OK");
}
private static LazyMan lazyMan;
//双重检测锁模式的 懒汉式单例 DCL懒汉式
public static LazyMan getInstance(){
if(lazyMan==null){
lazyMan = new LazyMan();//不是一个原子性操作
}
return lazyMan;
}
/*
* 1.分配内存空间
* 2、执行构造方法,初始化对象
* 3、把这个对象指向者个空间
*
* 123
* 132 A
*
* B //此时lazyMan还没有完成构造
*
* */
//多线程并发
public static void main(String[] args) {
for (int i = 0; i < 10; i++) {
new Thread(()->{
LazyMan.getInstance();
}).start();
}
}
}
DCL懒汉式
注意:synchronized 解决并发问题,但是因为lazyMan = new LazyMan();不是原子性操作(可以分割,见代码注释),可能发生指令重排序的问题,通过volatil来解决
- Java 语言提供了 volatile和 synchronized 两个关键字来保证线程之间操作的有序性,volatile 是因为其本身包含“禁止指令重排序”的语义,synchronized 是由“一个变量在同一个时刻只允许一条线程对其进行 lock 操作”这条规则获得的,此规则决定了持有同一个对象锁的两个同步块只能串行执行。
- 原子性就是指该操作是不可再分的。不论是多核还是单核,具有原子性的量,同一时刻只能有一个线程来对它进行操作。简而言之,在整个操作过程中不会被线程调度器中断的操作,都可认为是原子性。比如 a = 1;
public class LazyMan {
private LazyMan(){
System.out.println(Thread.currentThread().getName()+"OK");
}
// volatile 禁止指令重排
private volatile static LazyMan lazyMan;
//双重检测锁模式的 懒汉式单例 DCL懒汉式
public static LazyMan getInstance(){
if(lazyMan==null){
synchronized (LazyMan.class){//synchronized加锁解决多线程下的问题
if(lazyMan == null){
lazyMan = new LazyMan();//不是一个原子性操作
}
}
}
return lazyMan;
}
/*
* 1.分配内存空间
* 2、执行构造方法,初始化对象
* 3、把这个对象指向者个空间
*
* 123
* 132 A
*
* B //此时lazyMan还没有完成构造
*
* */
//多线程并发
public static void main(String[] args) {
for (int i = 0; i < 10; i++) {
new Thread(()->{
LazyMan.getInstance();
}).start();
}
}
}
静态内部类
//静态内部类
public class Holder {
//构造器私有
private Holder(){
}
public static Holder getInstance(){
return InnerClass.HOLDER;
}
public static class InnerClass{
private static final Holder HOLDER = new Holder();
}
}
单例不安全,反射破坏(见注释及main方法中反射破解步骤)
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
//单例懒汉式
//懒汉式单例
public class LazyMan {
//红绿等解决通过反射创建对象(反编译可以破解该方法)
private static boolean qingjiang = false;
private LazyMan(){
synchronized (LazyMan.class){
if (qingjiang==false){
qingjiang = true;
}else{
throw new RuntimeException("不要试图使用反射破坏单例");
}
}
System.out.println(Thread.currentThread().getName()+"OK");
}
private volatile static LazyMan lazyMan;//volatile避免指令重排
//双重检测锁模式的 懒汉式单例 DCL懒汉式
public static LazyMan getInstance(){
if(lazyMan==null){
lazyMan = new LazyMan();//不是一个原子性操作
}
return lazyMan;
}
//反射!
public static void main(String[] args) throws Exception {
//LazyMan instance = LazyMan.getInstance();
Field qingjiang = LazyMan.class.getDeclaredField("qingjiang");
qingjiang.setAccessible(true);
Constructor<LazyMan> declaredConstructor =LazyMan.class.getDeclaredConstructor(null);
declaredConstructor.setAccessible(true);//无视私有的构造器
LazyMan instance1 = declaredConstructor.newInstance();
qingjiang.set(instance1,false);
System.out.println(instance1);
LazyMan instance2 = declaredConstructor.newInstance();
System.out.println(instance2);
}
/*
* 1.分配内存空间
* 2、执行构造方法,初始化对象
* 3、把这个对象指向者个空间
*
* 123
* 132 A
*
* B //此时lazyMan还没有完成构造
*
* */
//多线程并发
/* public static void main(String[] args) {
for (int i = 0; i < 10; i++) {
new Thread(()->{
LazyMan.getInstance();
}).start();
}
}*/
}
枚举: 通过反射破解枚举发现不成功:
1、普通的反编译会欺骗开发者,说enum枚举是无参构造
2、实际enum为有参构造(见后面);
3、通过反射破解枚举会发现抛出异常
Exception in thread “main” java.lang.IllegalArgumentException: Cannot reflectively create enum objects at java.lang.reflect.Constructor.newInstance(Constructor.java:417) at com.ph.single.Test.main(EnumSingle.java:19)
import java.lang.reflect.Constructor;
//enmu是什么?本身也是一个class类
public enum EnumSingle {
INSTANCE;
public EnumSingle getInstance(){
return INSTANCE;
}
}
class Test{
public static void main(String[] args) throws Exception {
EnumSingle instance = EnumSingle.INSTANCE;
Constructor<EnumSingle> declaredConstructor = EnumSingle.class.getDeclaredConstructor(String.class,int.class);
declaredConstructor.setAccessible(true);
EnumSingle instance2 = declaredConstructor.newInstance();
//java.lang.NoSuchMethodException: com.ph.single.EnumSingle.<init>()
System.out.println(instance);
System.out.println(instance2);
}
}
通过idea和jdk自带的反编译枚举如下:
通过jad反编译枚举的代码如下
5、工厂模式
-
作用:
- 实现了创建者和调用者的分离
- 详细分类
- 简单工厂模式
- 工厂方法模式
- 抽象工厂模式
-
OOP七大原则
- 开闭原则: 一个软件的实体应当对扩展开放, 对修改关闭
- 依赖倒转原则: 要针对接口编程, 不要针对实现编程
- 迪米特法则: 只与你直接的朋友通信, 而避免和陌生人通信
-
核心本质
- 实例化对象不使用new, 用工厂方法代替
- 将选择实现类, 创建对象统一管理和控制. 从而将调用者跟我们的实现类解耦
-
三种模式:
-
简单工厂模式
-
用来生产统一等级结构中的任意产品(对于增加新的产品,需要复写已有代码)
-
工厂方法模式
- 用来生产同一等级结构中的固定产品(支持增加任意产品)
-
抽象工厂模式
- 围绕一个超级工厂创建其他工厂, 该超级工厂又称为其他工厂的工厂
-
1、简单工厂模式
Car
package com.kuang.factory.simple;
public interface Car {
void name();
}
Tesla
package com.kuang.factory.simple;
public class Tesla implements Car {
public void name() {
System.out.println("特斯拉");
}
}
WuLing
package com.kuang.factory.simple;
public class WuLing implements Car {
public void name() {
System.out.println("五菱宏光");
}
}
CarFactory
package com.kuang.factory.simple;
public class CarFactory {
//静态工厂模式
//增加一个新的产品如果不修改代码做不到
//方法一
public static Car getCar(String car){
if (car.equals("五菱宏光")){
return new WuLing();
}else if(car.equals("特斯拉")){
return new Tesla();
}else return null;
}
//方法二
public static Car getWuLing(){
return new WuLing();
}
public static Car getTesla(){
return new Tesla();
}
}
Consumer
package com.kuang.factory.simple;
public class Consumer {
public static void main(String[] args) {
//接口,所有实现类
Car wuLing = new WuLing();
Car tesla = new Tesla();
wuLing.name();
tesla.name();
wuLing=CarFactory.getCar("五菱宏光");
tesla=CarFactory.getCar("特斯拉");
wuLing.name();
tesla.name();
}
}
2、工厂方法模式
Car
package com.kuang.factory.method;
public interface Car {
void name();
}
CarFactory
package com.kuang.factory.method;
public interface CarFactory {
//工厂方法模式
Car getCar();
}
Tesla
package com.kuang.factory.method;
public class Tesla implements Car {
public void name() {
System.out.println("特斯拉");
}
}
TeslaFactory
package com.kuang.factory.method;
public class TeslaFactory implements CarFactory {
public Car getCar() {
return new Tesla();
}
}
WuLing
package com.kuang.factory.method;
public class WuLing implements Car {
public void name() {
System.out.println("五菱宏光");
}
}
WuLingFactory
package com.kuang.factory.method;
public class WuLingFactory implements CarFactory {
public Car getCar() {
return new WuLing();
}
}
Consumer
package com.kuang.factory.method;
import com.kuang.factory.simple.CarFactory;
import com.kuang.factory.simple.Tesla;
import com.kuang.factory.simple.WuLing;
public class Consumer {
public static void main(String[] args) {
//接口,所有实现类
Car wuLing = new WuLingFactory().getCar();
Car tesla = new TeslaFactory().getCar();
wuLing.name();
tesla.name();
}
//结构复杂度: simple
//代码复杂度: simple
//编程复杂度: simple
//管理上的复杂度: simple
//舰据设计原则:工厂方法模式!
//根据实际业务:简单工厂模式!
}
标签:23,模式,class,public,static,new,设计模式,LazyMan
From: https://www.cnblogs.com/smountain/p/16928810.html