前言
本篇主要介绍一下Java中的一些常见设计模式,也就是我们开发中经常使用的几种模式。还有更多的使用比较少,就不做详细介绍了。
总体来说的设计模式分为三大类:
- 创建型模式:工厂模式,抽象工厂模式,单例模式,建造者模式,原型模式。
- 结构型模式:适配器模式,代理模式,装饰器模式,外观模式,桥接模式,组合模式,享元模式。
- 行为型模式:观察者模式,策略模式,模板方法模式,迭代子模式,责任链模式,命令模式,备忘录模式,状态模式,访问者模式,解释器模式,中介者模式。
其实软件涉及模式并不是java 自己独有的。设计模式只是一种逻辑的总结归纳。其他的开发语言中也是一样可以实现的。
下面介绍一些常见,常用的几种设计模式。
工厂模式 Factory Pattern
通常我们说工厂模式,指的都是工厂方法模式。相较于它还有一个抽象工厂模式。
在工厂模式中,我们在创建对象时不会对客户端暴露创建逻辑,并且是通过使用一个共同的接口来指向新创建的对象。
//创建一个对象的 基础接口。
public interface Sender {
public void Send();
}
//创建一个 邮件发送子对象
public class MailSender implements Sender {
@Override
public void Send() {
System.out.println("我是一个邮件发送者");
}
}
//创建一个 短信发送子对象。
public class SmsSender implements Sender {
@Override
public void Send() {
System.out.println("我是一个短信发送者");
}
}
//创建一个 发送工厂。
public class SendFactory {
//根据类型,获取相应的发送对象。 外界不需要关心是如何发送的,只是根据需求得到相应的实例对象。
public Sender produce(String type) {
if ("mail".equals(type)) {
return new MailSender();
} else if ("sms".equals(type)) {
return new SmsSender();
} else {
return null;
}
}
}
我们如果不想传type 对象,我们也可以创建多个不同的实例。这样其他人只需要了解接口类Sender的使用就可以了。不用在意具体的实现。
public class SendFactory {
//根据类型,获取相应的发送对象。 外界不需要关心是如何发送的,只是根据需求得到相应的实例对象。
public Sender produceMail() {
return new MailSender();
}
public Sender produceSms() {
return new SmsSender();
}
}
在上面的工厂对象调用时,我们需要创建一个SendFactory对象。然后再调用。我们如果给方法添加上static就是所谓的静态工厂方法模式。
实例:
public class SendFactory {
public static Sender produceMail() {
return new MailSender();
}
public static Sender produceSms() {
return new SmsSender();
}
}
抽象工厂模式 Abstract Factory Pattern
在抽象工厂模式中,接口是负责创建一个相关对象的工厂,不需要显式指定它们的类。每个生成的工厂都能按照工厂模式提供对象。
工厂方法模式有一个问题就是,类的创建依赖工厂类。如果想要拓展程序,必须对工厂类进行修改,而这种情况违背了闭包原则。
针对这种情况,就出来了抽象工厂模式。这样一旦需要增加新的功能,直接增加新的工厂类就可以了。
示例:
public interface Sender {
public void Send();
}
public class MailSender implements Sender {
@Override
public void Send() {
System.out.println("发送邮件");
}
}
public class SmsSender implements Sender {
@Override
public void Send() {
System.out.println("发送短信");
}
}
//抽象接口
public interface Provider {
public Sender produce();
}
//创建一个 短信发送工厂
public class SendSmsFactory implements Provider{
public Sender produce(String type) {
return new SmsSender();
}
}
//创建一个 邮件发送工厂
public class SendMailFactory implements Provider{
public Sender produce(String type) {
return new MailSender();
}
}
//上面示例使用接口实现的抽象,我们也可以使用抽象类来实现
public abstract class SendProvider{
public abstract Sender produce();
}
单例模式 Singleton Pattern
可以说是最简单的一种设计模式了。它的要求是:保证一个类仅有一个实例,并提供一个访问它的全局访问点。它不需要再额外创建实例化。
特性总结下就是:
- 只能有一个实例。(构造函数私有化 private)
- 必须由它自己创建自己的唯一实例。(自身初始化创建)
- 必须给所有其他对象提供访问该实例的方法。(静态全局函数获取实例)
它主要是为了减少类的频繁创建于销毁。当我们有个实例对象,在整个程序各种模块都要使用的时候,我们通过单例模式可以有效减少类的重复创建于销毁,减少内存的开销。
public class SingleObject {
//自己创建 SingleObject 的静态对象
private static SingleObject instance = new SingleObject();
//让构造函数私有化,这样该类就不会被实例化
private SingleObject(){}
//给其他对象提供访问实例的静态方法。
public static SingleObject getInstance(){
return instance;
}
}
上面的初始化逻辑叫做:饿汉式单例对象。
还有一种叫做懒汉式。
实例:
public class SingleObject {
//自己创建 SingleObject 的静态对象
private static Singleton instance;
//让构造函数私有化,这样该类就不会被实例化
private SingleObject(){}
//给其他对象提供访问实例的静态方法。
public static Singleton getInstance() {
if (instance == null) {
instance = new Singleton();
}
return instance;
}
}
还有更复杂的,线程安全处理,多线程状态下的验证等变种。
这里就不复杂拓展了,有感兴趣的可以通过 单例模式 | 菜鸟教程 (runoob.com)了解吧。
建造者模式 Builder Pattern
主要解决在软件系统中,有时候面临着"一个复杂对象"的创建工作,其通常由各个部分的子对象用一定的算法构成;由于需求的变化,这个复杂对象的各个部分经常面临着剧烈的变化,但是将它们组合在一起的算法却相对稳定。
而建造者模式则是将各种产品集中起来进行管理,用来创建复合对象, 所谓复合对象就是指某个类具有不同的属性。
public interface Sender {
public void Send();
}
public class MailSender implements Sender {
@Override
public void Send() {
System.out.println("发送邮件");
}
}
public class SmsSender implements Sender {
@Override
public void Send() {
System.out.println("发送短信");
}
}
public class Builder {
private List<Sender> list = new ArrayList<Sender>();
public void produceMailSender(int count) {
for (int i = 0; i < count; i++) {
list.add(new MailSender());
}
}
public void produceSmsSender(int count) {
for (int i = 0; i < count; i++) {
list.add(new SmsSender());
}
}
}
适配器模式 Adapter Pattern
适配器模式是作为两个不兼容的接口之间的桥梁。
将某个类的接口转换成客户端期望的另一个接口表示,目的是消除由于接口不匹配所造成的类的兼容性问题。
public interface MediaPlayer {
public void play(String audioType, String fileName);
}
public interface AdvancedMediaPlayer {
public void playVlc(String fileName);
public void playMp4(String fileName);
}
public class VlcPlayer implements AdvancedMediaPlayer{
@Override
public void playVlc(String fileName) {
System.out.println("Playing vlc file. Name: "+ fileName);
}
@Override
public void playMp4(String fileName) {
}
}
public class Mp4Player implements AdvancedMediaPlayer{
@Override
public void playVlc(String fileName) {
//什么也不做
}
@Override
public void playMp4(String fileName) {
System.out.println("Playing mp4 file. Name: "+ fileName);
}
}
public class MediaAdapter implements MediaPlayer {
AdvancedMediaPlayer advancedMusicPlayer;
public MediaAdapter(String audioType){
if(audioType.equalsIgnoreCase("vlc") ){
advancedMusicPlayer = new VlcPlayer();
} else if (audioType.equalsIgnoreCase("mp4")){
advancedMusicPlayer = new Mp4Player();
}
}
@Override
public void play(String audioType, String fileName) {
if(audioType.equalsIgnoreCase("vlc")){
advancedMusicPlayer.playVlc(fileName);
}else if(audioType.equalsIgnoreCase("mp4")){
advancedMusicPlayer.playMp4(fileName);
}
}
}
public class AudioPlayer implements MediaPlayer {
MediaAdapter mediaAdapter;
@Override
public void play(String audioType, String fileName) {
//播放 mp3 音乐文件的内置支持
if(audioType.equalsIgnoreCase("mp3")){
System.out.println("Playing mp3 file. Name: "+ fileName);
}
//mediaAdapter 提供了播放其他文件格式的支持
else if(audioType.equalsIgnoreCase("vlc")
|| audioType.equalsIgnoreCase("mp4")){
mediaAdapter = new MediaAdapter(audioType);
mediaAdapter.play(audioType, fileName);
}
else{
System.out.println("Invalid media. "+
audioType + " format not supported");
}
}
}
public class AdapterPatternDemo {
public static void main(String[] args) {
AudioPlayer audioPlayer = new AudioPlayer();
audioPlayer.play("mp3", "beyond the horizon.mp3");
audioPlayer.play("mp4", "alone.mp4");
audioPlayer.play("vlc", "far far away.vlc");
audioPlayer.play("avi", "mind me.avi");
}
}
观察者模式 Observer Pattern
观察者模式很好理解,类似于订阅和关注。
当我们在抖音或微博中,关注了博主后。博主之后发布新的消息,你就能够收到推送。
简单来讲就一句话:当一个对象变化时, 其它依赖该对象的对象都会收到通知,并且随着变化。对象之间是一种一对多的关系。我们可以观察多个对象,去接收它们的变化通知。
//观察者
public interface Observer {
public void update();
}
//观察者A
public class ObserverA implements Observer {
@Override
public void update() {
System.out.println("observerA 收到");
}
}
//观察者B
public class ObserverB implements Observer {
@Override
public void update() {
System.out.println("observerB 收到");
}
}
public interface Subject {
/*增加观察者*/
public void add(Observer observer);
/*删除观察者*/
public void del(Observer observer)
/*通知观察者*/
public void notifyObservers();
/*自己的业务处理*/
public void myaction();
}
public abstract class AbstractSubject implements Subject {
private Vector<Observer> vector = new Vector<Observer>();
@Override
public void add(Observer observer) {
vector.add(observer);
}
@Override
public void del(Observer observer) {
vector.remove(observer);
}
@Override
public void notifyObservers() {
Enumeration<Observer> enumo = vector.elements();
while (enumo.hasMoreElements()) {
enumo.nextElement().update();
}
}
}
public class MySubject extends AbstractSubject {
@Override
public void myaction() {
System.out.println("本身进行更新");
notifyObservers();
}
}
public class ObserverTest {
public static void main(String[] args) {
Subject sub = new MySubject();
sub.add(new ObserverA());
sub.add(new ObserverB());
sub.operation();
}
}
到这里,主要介绍了几种常见的。还有更多的设计模式大家可以深入了解一下。
设计模式是一个很有用的知识。当你弄明白了各种设计模式,你再去看各种源代码你将更能直观了解代码的作用。
否则阅读会磕磕碰碰。
评论区