Java常见几种设计模式
什么是设计模式?
设计模式是可以重复利用的解决方案。软件开发的先辈们将在开发过程中遇到的问题进行总结,并给出解决方案。后辈在遇到类似问题时,可以使用这些方案解决问题。(从设计模式可以看出,先辈们对于接口的应用。)
• 单例模式(ps:参考https://www.cnblogs.com/xiaofengwang/p/11255678.html)
一个类只有一个实例对象。这个对象的构造器被private修饰,所以不能在其他地方new,只能通过getInstance()获得实例。
单例模式的几种写法(还有其他的写法):
○ 懒汉式(加上synchronized 关键字,变成线程安全的。)
1 public class Singleton 2 { 3 private static Singleton instance; 4 private Singleton(){} 5 public static synchronized Singleton getInstance(){ 6 if(instance == null){ 7 instance = new Singleton(); 8 } 9 return instance; 10 } 11 }
○ 饿汉式
public class Singleton { private static Singleton instance = new Singleton(); private Singleton(){} public static Singleton getInstance(){ return instance; } }
○ 双重检验锁(不仅能够避免线程安全问题,还能防止反序列化重新创建对象。)
public class Singleton { private volatile static Singleton singleton; private Singleton (){} public static Singleton getSingleton() { if (singleton == null) { synchronized (Singleton.class) { if (singleton == null) { singleton = new Singleton(); } } } return singleton; } }
• 观察者模式:
观察者设计模式,定义了一种一对多的关联关系。一个对象 A 与多个对象 B、C、D 之间建立“被观察与观察关系”。当对象 A 的状态发生改变时,会通知所有观察者对象 B、 C、 D。当B、C、D 在接收到 A 的状态改变通知后,根据自身实际情况,做出相应改变。通常观察者和被观察者都是接口,上面所提到的对象是指实现了这些接口的对象。
观察者接口:
package com.bzw.observer; public interface Observer { //接到通知后,要做的具体处理 void handleNotify(String message); }
被观察者接口:
package com.bzw.observer; public interface ToBeObservered { public void addObserver(Observer observer); public void removeObserver(Observer observer); public void notifyObserver(String message); }
创建观察者:
package com.bzw.observer; public class ObserverA implements Observer{ @Override public void handleNotify(String message) { System.out.println(message+"A正在处理通知"); } } package com.bzw.observer; public class ObserverB implements Observer{ @Override public void handleNotify(String message) { System.out.println(message+"B正在处理通知"); } }
创建被观察者:
package com.bzw.observer; import java.util.ArrayList; import java.util.List; public class Observered implements ToBeObservered{ List<Observer> observers = new ArrayList<>(); @Override public void addObserver(Observer observer) { observers.add(observer); } @Override public void removeObserver(Observer observer) { observers.remove(observer); } @Override public void notifyObserver(String message) { for(Observer o : observers) { o.handleNotify(message); } } }
测试类:
package com.bzw.observer; public class ObserverTest { public static void main(String args[]) { ObserverA xiaowang = new ObserverA(); ObserverB xiaoli = new ObserverB(); Observered beauty = new Observered(); beauty.addObserver(xiaowang); beauty.addObserver(xiaoli); beauty.notifyObserver("快来呀"); // System.out.println("----------------------"); // beauty.removeObserver(xiaoli); // beauty.notifyObserver("再来呀"); } }
• 装饰者模式
对某个对象功能进行拓展时,可以考虑用装饰者模式。
优点:不用修改被修饰对象的源码,装饰者与被装饰者耦合度不高。
package com.bzw.decorate; /** * * 面条装饰器 * */ public interface NoodleDecorate { public void addThings(); }
package com.bzw.decorate; public class Noodle implements NoodleDecorate{ /** * 普通拉面 */ @Override public void addThings() { System.out.println("两片牛肉"); System.out.println("一根胡萝卜"); System.out.println("三根香菜"); } }
package com.bzw.decorate; public class ChiliNoodle implements NoodleDecorate{ private Noodle noodle; //将普通拉面对象传入 public ChiliNoodle(Noodle noodle) { this.noodle = noodle; } @Override //对普通拉面进行修饰 public void addThings() { noodle.addThings(); System.out.println("加三勺辣椒"); } }
测试类:
package com.bzw.decorate; public class NoodleTest { public static void main(String args[]) { Noodle noodle = new Noodle(); ChiliNoodle cn = new ChiliNoodle(noodle); cn.addThings(); } }
• 适配器模式(ps :参考https://www.cnblogs.com/luohanguo/p/10334291.html)
可以让原本接口不一致的类可以一起工作。有三种方式:类的适配器模式,对象适配器模式,接口适配器模式。其中对象适配器模式和接口适配器模式可以较小程度的修改源码,代码耦合度低。当不希望实现接口中的所有方法时,可以用接口适配器模式,其他情况建议用对象适配器模式。
第一种方式:
package com.bzw.adapter; public class Phone { public void typecPhone() { System.out.println("信息从typec口的手机输入。"); } } package com.bzw.adapter; public interface Vga { void vgaInterface(); }
package com.bzw.adapter; /* * 适配器第一种方式:类的适配器模式 */ public class TypecVga1 extends Phone implements Vga{ @Override public void vgaInterface() { typecPhone(); System.out.println("接收到typec口信息,转到vga接口中...."); System.out.println("信息已转成vga,可以与显示屏对接"); } }
第二种方式:
Phone类和Vga接口和方式一一样。
package com.bzw.adapter; /* * 第二种方式:对象适配器模式 */ public class TypecVga2 implements Vga{ private Phone phone; public TypecVga2(Phone phone) { this.phone = phone; } @Override public void vgaInterface() { if(phone != null) { phone.typecPhone(); System.out.println("接收到typec口信息,转到vga接口中...."); System.out.println("信息已转成vga,可以与显示屏对接"); } } }
测试类:
package com.bzw.adapter; public class Screen { public static void main(String args[]) { System.out.println("----------第一种方式-------------"); TypecVga1 adapter1 = new TypecVga1(); adapter1.vgaInterface(); System.out.println("----------显示屏与适配器连接,手机成功投影到显示器------------"); System.out.println("\n"); System.out.println("----------第二种方式--------------"); Phone phone = new Phone(); TypecVga2 adapter2 = new TypecVga2(phone); adapter2.vgaInterface(); System.out.println("----------显示屏与适配器连接,手机成功投影到显示器------------"); } }
第三种方式:
package com.bzw.adapter.TypecVga3; /* * 第三种方式:接口的适配器模式 */ //在这个接口中可以定义多个抽象方法。 public interface Target { public void typec(); public void typecVga(); public void typecHdmi(); } package com.bzw.adapter.TypecVga3; //抽象类实现接口中的所有方法,这样就意味着抽象方法被实现了,子类在继承时, //可以有选择性的重写。 public abstract class Adapter implements Target{ public void typec() {}; public void typecVga() {}; public void typecHdmi() {}; } package com.bzw.adapter.TypecVga3; public class VgaAdapter extends Adapter{ public void typec() { System.out.println("信息从typec口的手机输入。"); } public void typecVga() { System.out.println("接收到typec口信息,转到vga接口中...."); System.out.println("信息已转成vga,可以与显示屏对接"); } /**可以根据需要选择要重写的方法。 public void typecHdmi() { System.out.println("接收到typec口信息,转到HDMI接口中...."); System.out.println("信息已转成HDMI,可以与显示屏对接"); }*/ }
测试类:
package com.bzw.adapter.TypecVga3; public class Screen { public static void main(String arg[]) { System.out.println("---------第三种方式----------------"); VgaAdapter adapter3 = new VgaAdapter(); adapter3.typec(); adapter3.typecVga(); System.out.println("----------显示屏与适配器连接,手机成功投影到显示器------------"); } }
• 代理模式
为一个对象提供一个代理以控制外界对该对象的访问。
○ 静态代理:代理类和相关方法直接在代码中写死。
○ 动态代理:可以直接给某一个目标对象生成一个代理对象,二不需要代理类的存在。
代理模式的优点:
○ 提高程序的扩展性和可复用性。(动态代理)
○ 保护对象。
• 工厂模式
用工厂提供的方法代替使用new创建对象的操作,将创建对象统一管理和控制从而将调用者与实现类进行解耦,实现创建者与调用者的分离。
实现工厂模式的三种方式:
○ 简单工厂模式(静态工厂):实际上它并不算是设计模式,只不过算是工厂方法和抽象工厂的基础,不过也有一些运用的地方。比如jdk的动态代理的Proxy.newProxyInstance这个就是一个简单工厂。
○ 工厂方法:工厂方法模式的实质是定义一个用于创建对象的接口,然后让实现这个接口的类来决定创建哪个类的对象。
○ 抽象工厂:抽象工厂模式提供了一种方式,可以将同一产品族的单独的工厂封装起来。在正常使用中,客户端程序需要创建抽象工厂的具体实现,然后使用抽象工厂作为接口来创建这一主题的具体对象。
对象适配器模式是其他6种结构型设计模式的起源。
三种方式总结:
○ 静态工厂 : 用来生产同一等级结构中的任意产品。产品的创建是由你传入参数决定的。
○ 工厂方法 :用来生产同一等级结构中的固定产品。一个工厂只能生产一个固定的产品。
○ 抽象工厂 :用来生产不同产品族的全部产品。一个工厂可以生产跟该产品相关的一系列产品。