设计模式学习

tech2024-06-02  73

面向对象开发设计原则:

   开闭原则:        对类只允许拓展不允许修改,

  里氏替换原则: 子类可以扩展父类的功能,但不能改变父类原有的功能。也就是说:子类继承父类时,除添加新的方法完成新                              增功能外,尽量不要重写父类的方法。

  依赖倒置原则:高层模块不应该依赖低层模块,两者都应该依赖其抽象;抽象不应该依赖细节,细节应该依赖抽象。其核心思                               想是:要面向接口编程,不要面向实现编程。

  单一职责原则:这里的职责是指类变化的原因,单一职责原则规定一个类应该有且仅有一个引起它变化的原因,否则类应该被                               拆 分

 接口隔离原则:要求程序员尽量将臃肿庞大的接口拆分成更小的和更具体的接口,让接口中只包含客户感兴趣的方法接口尽量                              小,但是要有限度。一个接口只服务于一个子模块或业务逻辑。提高内聚,减少对外交互。使接口用最少的方法                            去完成最多的事情。

 迪米特法则: 如果两个软件实体无须直接通信,那么就不应当发生直接的相互调用,可以通过第三方转发该调用。其目的是降                           低 类之间的耦合度,提高模块的相对独立性。

 合成复用原则:要求在软件复用时,要尽量先使用组合或者聚合等关联关系来实现,其次才考虑使用继承关系来实现。如果要使                            用继承关系,则必须严格遵循里氏替换原则。合成复用原则同里氏替换原则相辅相成的,两者都是开闭原则的具                            体实现规范。

 

 

设计模式:

 

单例工厂适配器装饰器代理观察者建造者桥接过滤器原型组合外观享元责任链命令解释器迭代器中介备忘录状态空对象策略模板访问者MVC业务代表组合实体数据访问对象前端控制器拦截过滤器服务定位器传输对象抽象工厂   

设计模式分类: 

1. 根据目的来分

根据模式是用来完成什么工作来划分,这种方式可分为创建型模式、结构型模式和行为型模式 3 种。

创建型模式:用于描述“怎样创建对象”,它的主要特点是“将对象的创建与使用分离”。GoF 中提供了单例、原型、工厂方法、抽象工厂、建造者等 5 种创建型模式。结构型模式:用于描述如何将类或对象按某种布局组成更大的结构,GoF 中提供了代理、适配器、桥接、装饰、外观、享元、组合等 7 种结构型模式。行为型模式:用于描述类或对象之间怎样相互协作共同完成单个对象都无法单独完成的任务,以及怎样分配职责。GoF 中提供了模板方法、策略、命令、职责链、状态、观察者、中介者、迭代器、访问者、备忘录、解释器等 11 种行为型模式。

2. 根据作用范围来分

根据模式是主要用于类上还是主要用于对象上来分,这种方式可分为类模式和对象模式两种。

类模式:用于处理类与子类之间的关系,这些关系通过继承来建立,是静态的,在编译时刻便确定下来了。GoF中的工厂方法、(类)适配器、模板方法、解释器属于该模式。对象模式:用于处理对象之间的关系,这些关系可以通过组合或聚合来实现,在运行时刻是可以变化的,更具动态性。GoF 中除了以上 4 种,其他的都是对象模式。

 

 

 

单例模式:

       懒汉模式:

         

public class LazySingleton { //私有的静态的实例 private static LazySingleton instance ; //private static volatile SimpleSingleton instance = null; //私有的无参构造器constractor private LazySingleton(){} //共有的获取对象的方法 public static LazySingleton getInstance() throws InterruptedException, NoSuchAlgorithmException { if (instance == null){ //在这判断的时候可能其他线程已经过来创建实例,同时创建实例 Thread.sleep(10000); //如果多个线程同时进入到这,就可能会产生多个对象实例 instance = new LazySingleton(); } return instance; } public static void main(String[] args) { long startTime = System.currentTimeMillis(); System.out.println("startTime===>"+startTime); for (int i = 0; i <50; i++) { new Thread(new Runnable() { @Override public void run() { for (int j = 0; j < 20; j++) { try { System.out.println("第"+j+"层次的得到的对象值为"+LazySingleton.getInstance()); } catch (InterruptedException e) { e.printStackTrace(); } catch (NoSuchAlgorithmException e) { e.printStackTrace(); } } } }).start(); } long endTime = System.currentTimeMillis(); System.out.println("endTime===>"+endTime); System.out.println(endTime - startTime); } }

 

       饿汉模式:

package com.wxj.gof.singleton; /** * 饿汉模式,不能延时加载 * 饿汉模式不会出现多线程情景下,生成多个实例的情况, * 加上static修饰,实例不属于对象,属于类 */ public class HungerSingleton { private static HungerSingleton singleton = new HungerSingleton(); private HungerSingleton(){} public static HungerSingleton getInstance(){ return singleton; } public static void main(String[] args) { for (int i = 0; i <100; i++) { new Thread(new Runnable() { @Override public void run() { for (int j = 0; j < 10; j++) { System.out.println("第"+j+"层次的得到的对象值为"+HungerSingleton.getInstance()); } } }).start(); } } }

 

        静态内部类加载:

/** * 静态内部类单例模式,线程安全的,延时加载 */ public class MyStaticSingleton { private MyStaticSingleton(){} private static class InstanceHolder{ private final static MyStaticSingleton instance = new MyStaticSingleton(); } public static MyStaticSingleton getInstance(){ //调用内部类属性 return InstanceHolder.instance; } public static void main(String[] args) { System.out.println(InstanceHolder.instance); System.out.println(InstanceHolder.instance); } }

                    静态内部类单例模式也称单例持有者模式,实例由内部类创建,由于 JVM 在加载外部类的过程中, 是不会加载静态  内部类的, 只有内部类的属性/方法被调用时才会被加载, 并初始化其静态属性。静态属性由static修饰,保证只被实例化一次,并且严格保证实例化顺序。

        枚举类加载:

/** * 枚举单例模式,不能延时加载,线程安全 */ public enum EnumSingleton { INSTANCE; public void doSomething(){ System.out.println("let's do something"); } public static void main(String[] args) { EnumSingleton.INSTANCE.doSomething(); System.out.println(EnumSingleton.INSTANCE); } }

 

        双重校验锁:

/** * 这种写法的单例模式看似完美无缺,但是有可能出现空指针异常,是因为jvm发生指令重排,即在构造函数操作太多,JVM可能在构造函数 * 还没有完全完成实例化,就把对象返回,就会造成空指针 * private volatile static DoubleCheckSingleton instance; volatile可以防止指令重排 */ public class DoubleCheckSingleton { //私有的实例 private volatile static DoubleCheckSingleton instance; //私有的无参构造器 private DoubleCheckSingleton(){} //获取单例 public static DoubleCheckSingleton getInstance() throws InterruptedException { if (null == instance){ Thread.sleep(1000); synchronized (DoubleCheckSingleton.class){ if(null == instance){ instance = new DoubleCheckSingleton(); } } } return instance; } public static void main(String[] args) { long startTime = System.currentTimeMillis(); System.out.println("startTime===>"+startTime); for (int i = 0; i <50; i++) { new Thread(new Runnable() { @Override public void run() { for (int j = 0; j < 20; j++) { try { System.out.println("第"+j+"层次的得到的对象值为"+ DoubleCheckSingleton.getInstance()); } catch (InterruptedException e) { e.printStackTrace(); } } } }).start(); } long endTime = System.currentTimeMillis(); System.out.println("endTime===>"+endTime); System.out.println(endTime - startTime); } }

                    面的双重检测锁模式看上去完美无缺,其实是存在问题,在多线程的情况下,可能会出现空指针问题,出现问题的原  因是JVM在实例化对象的时候会进行优化和指令重排序操作。

 

         *1 除枚举方式外, 其他方法都会通过反射的方式破坏单例,反射是通过调用构造方法生成新的对象,所以如果我们想要阻止单例破坏,可以在构造方法中进行判断,若已有实例, 则阻止生成新的实例,如在无参构造中:

             

private SingletonObject1(){ if (instance !=null){ throw new RuntimeException("实例已经存在,请通过 getInstance()方法获取"); } }

         2如果单例类实现了序列化接口Serializable, 就可以通过反序列化破坏单例,所以我们可以不实现序列化接口,如果非得实现序列化接口,可以重写反序列化方法readResolve(), 反序列化时直接返回相关单例对象。

public Object readResolve() throws ObjectStreamException { return instance; }

 

工厂模式:

 

 

抽象工厂模式:

 

适配器模式:

 

代理模式:

 

 

 

         

        

 

 

 

最新回复(0)