常用设计模式

本文探讨了软件设计的六大原则,聚焦于降低类间耦合,涵盖单例模式、工厂模式、建造者模式等创建型模式,以及策略模式、模板方法模式和观察者模式的行为型设计。实例解析了每种模式的应用场景和实现方法,帮助理解如何在实际项目中高效利用这些设计思想。

六大原则–核心是降低类间的耦合

单一职责原则
一个类只负责一个变化
开放封闭原则
开发是指扩展是开发的,修改是封闭。
里氏代换原则
使用的基类的地方可以都可以被其子类,完美的替换基类。
要求:子类的方法都必须在父类中进行声明。( 用子类来代替父类,只能调用父类中声明的方法,但在运行期,我们实际执行的是子类重写父类的方法。
实际上:父类一般是抽象或者接口,子类是实现类
依赖倒置原则
高低层模块不相互依赖,两者都依赖抽象;细节应该依赖抽象
高层模块是指调用者,低层模块是指具体实现类
在java中的表现:模块间是通过抽象类或者接口来实现的。
迪米特法则(最少知道原则)
一个对象要尽可能减少对其他对象的了解
实现:两个对象通过第三方来调用对方的方法
接口隔离原则
使用多个隔离的接口比使用有大量方法的接口好

创建型设计模式

单例模式

定义:保证一个类只有一个实例,并且提供一个访问该全局的访问点
(DCL)

java版

class Bank{

    private Bank(){}

    private volatile static Bank instance = null;

    public static Bank getInstance(){
		if (instance == null) {//立牌坊通知
        synchronized (Bank.class) {
            if (instance == null) {
                instance = new Bank();
            }
        }
    }
    return instance;
}

kotlin版

class MediaPlayerHelp private constructor(context: Context){
    val mContext=context
    init {
        val mMediaPlayer= MediaPlayer()
    } //构造器执行的构造函数
    companion object{
        @Volatile private var instance:MediaPlayerHelp? =null
        fun getInstance(context: Context){
            instance?: synchronized(this){
                instance?: MediaPlayerHelp(context).also { instance=it }
            }
        }
    }
}

(静态内部类单例模式)
第一次加载Singleton类的时候不会初始化sinstance.因为内部类对于外部类来说也是一个字段,字段默认为null。只有在第一次调用getInstance时
虚拟机才会加载SingletonHolder,并初始化Sinstance.

public class Singleton {
    private Singleton(){}
    public static Singleton getInstance(){
        return SingletonHolder.sInstance;
    }
    private static class SingletonHolder{
        private static final Singleton sInstance=new Singleton();
    }
}

(枚举单例)
使用枚举实现单例模式,由jvm从根本上提供保障单例。
那些地方用到了单例模式
网站的计数器,应用程序的日志应用,Windows的(任务管理器)windows的(回收站)。

工厂模式

参考链接
定义:我们在创建对象时不会对客户端暴露创建逻辑,并且是通过使用一个共同的接口来指向新创建的对象
简单工厂模式:在工厂中就定义了可实例化的类型,如果要添加新的类型需要修改代码
在这里插入图片描述

工厂直接生产产品
工厂方法模式:最顶层的工厂里只有抽象方法,生成具体产品的任务分发给具体的产品工厂
在这里插入图片描述

concreteFactory1中的CreateProduct()的返回对象是AbstractProduct的实现子类

建造者模式

定义:将一个复杂对象的构建过程与表示分离开来,使得同样的构建过程可以创建不同的表示
在这里插入图片描述

Director为指挥者/导演类,负责安排已有模块的顺序,然后告诉Builder开始建造;
Dircector类里会有一个Bulider的字段,来安排Builder里的产品顺序。
Builder是抽象建造者,规范产品的组建,一般由子类实现;
ConcreteBuilder是具体建造者,实现抽象类定义的所有方法,并且返回一个组建好的对象;
Product是产品类,通常实现了模板方法模式
在实际中,Dircector构造器中传入一个具体的建设者,然后传入的建设者会按照director的安装方法来调用自己的组件,最后会返回一个产品

Director director = new Director();
 director.Construct(builder1);
 Product product1 = builder1.getResult();

优点:客户端不必知道产品内部组成的细节

在这里插入图片描述

结构性设计模式

代理模式

定义:给某一个对象提供一个代理对象,并由代理对象控制对原对象的引用。
在这里插入图片描述

抽象主题角色(Subject):声明了目标对象和代理对象的共同接口,
具体主题角色(RealSubject):也称为被代理角色。定义了代理对象所代表的目标对象。
代理主题角色(Proxy):也叫代理类。代理对象内部含有目标对象的引用,从而可以在任何时候操作目标对象;在其所实现的接口中调用RealSubject中的相应方法
动态代理:通过反射动态生成代理类
客户通过代理类来调用其它对象的方法,并且是在程序运行时根据需要动态创建目标类的代理对
象。
问题一:如何根据加载到内存中的被代理类,动态的创建一个代理类及其对象。
(通过Proxy.newProxyInstance()实现)
问题二:当通过代理类的对象调用方法a时,如何动态的去调用被代理类中的同名方法a。
(通过InvocationHandler接口的实现类及其方法invoke())
静态代理:在程序运行前,代理类的.class文件就已经存在了

2.2 静态代理的缺点:
① 代理类和目标对象的类都是 在编译期间确定下来,不利于程序的扩展。
② 每一个代理类只能为一个接口服务,这样一来程序开发中必然产生过多的代理。

装饰模式

定义:以对客户透明的方式动态地给一个对象附加上更多的责任。换言之,客户端并不会觉得对象在装饰前和装饰后有什么不同。装饰模式可以在不使用创造更多子类的情况下,将对象的功能加以扩展。
在这里插入图片描述

装饰(Decorator)角色:持一个构件(Component)对象的实例,并定义一个与抽象构件接口一致的接口。
在具体装饰上,会定义一些额外的功能,然后再抽象接口的实现函数中进行调用
ConcreteDecoratorA的方法
在这里插入图片描述

super.sampleOperation()是指Dector的方法,里面实现是组件的sampleOperation()方法。
然后具体装饰对象调用接口方法,比原先的具体组件调用接口方法实现的功能更多一些。

外观模式

定义:要求一个子系统的外部与内部的通信要通过一个统一的对象来进行
在这里插入图片描述

facade类中会有对各个子系统的引用,facade中的每一个方式都是调用子系统中相应的方法进行组合产生的
优点:减少了系统的相互依赖程度,所有的依赖都是对外观类的依赖(子系统的应用都是private,外观类的方法也是对子系统方法的引用)
加强了安全性,客户无法修改子系统的方法。

享元模式

定义:以共享的方式高效的支持大量的细粒度对象。
好处:减少应用程序创建的对象,降低程序内存的占用,提高程序的性能
享元对象区分内蕴状态(Internal State)和外蕴状态(External)。
一个内蕴状态是存储在享元对象内部的,并且是不会随环境改变而有所不同的。(作为创建对象的依据,一般作为map的key)
一个外蕴状态是随环境改变而改变的、不可以共享的状态。(可以根据不同的环境来创建对象的不同外蕴状态,(switch,case)
工厂类一般情况有一个map字段,用来存储不同内蕴状态的享元对象
在这里插入图片描述

如果一个享元对象有外蕴状态的话,所有的外部状态都必须存储在客户端,在使用享元对象时,再由客户端传入享元对象。
享元工厂角色类,必须指出的是,客户端不可以直接将具体享元类实例化,而必须通过一个工厂对象,利用一个factory()方法得到享元对象。

public class FlyweightFactory {
 2 
 3     //定义一个池容器
 4     private static HashMap<String, Flyweight> pool = new HashMap<>();
 5     
 6     //享元工厂
 7     public static Flyweight getFlyweight(String extrinsic) {
 8         Flyweight flyweight = null;
 9         
10         if(pool.containsKey(extrinsic)) {    //池中有该对象
11             flyweight = pool.get(extrinsic);
12             System.out.print("已有 " + extrinsic + " 直接从池中取---->");
13         } else {
14             //根据外部状态创建享元对象
15             flyweight = new ConcreteFlyweight(extrinsic);
16             //放入池中
17             pool.put(extrinsic, flyweight);
18             System.out.print("创建 " + extrinsic + " 并从池中取出---->");
19         }
20         
21         return flyweight;
22     }
23 }

当客户端需要单纯享元对象的时候,需要调用享元工厂的factory()方法,并传入所需的单纯享元对象的内蕴状态,由工厂方法产生所需要的享元对象。之后再由客户端对生产出来的对象进行外部状态的传入

 Flyweight flyweightX = FlyweightFactory.getFlyweight("X");
 7         flyweightX.operate(++ extrinsic);
 8         
 9         Flyweight flyweightY = FlyweightFactory.getFlyweight("Y");
10         flyweightY.operate(++ extrinsic);

使用场景:
需要大量相似的对象
需要缓存池

行为型设计模式

策略模式

定义:使算法定义独立于它的客户之外
在这里插入图片描述

环境类(Context)::该类的构造器中包含了 策略类,通过传入不同的具体策略来产生不同的效果。

public class Context {
    //持有一个具体策略的对象
    private Strategy strategy;
    public Context(Strategy strategy){
        this.strategy = strategy;
    }
    /**
     * 策略方法
     */
    public void contextInterface(){
        
        strategy.strategyInterface();
    }
    

抽象策略类(Strategy):定义所有支持的算法的公共接口。 Context使用这个接口来调用某ConcreteStrategy定义的算法。
具体策略类(ConcreteStrategy):以Strategy接口实现某具体算法。
环境类可以根据自足选择具体的策略类,减少if语句
与工厂模式的区别
我们去旅行。策略模式的做法:有几种方案供你选择旅行,选择火车好呢还是骑自行车,完全有客户自行决定去构建旅行方案(比如你自己需要去买火车票,或者机票)。而工厂模式是你决定哪种旅行方案后,不用关注这旅行方案怎么给你创建,也就是说你告诉我方案的名称就可以了,然后由工厂代替你去构建具体方案(工厂代替你去买火车票)。
缺点:
上层模块需要知道有哪些策略,才能使用这些策略,这违背了迪米特原则

模板方法模式

AbstractClass叫做抽象模板,它的方法分为两类:基本方法(由子类去实现)和模板方法(可以有一个或多个,也就是一个框架,实现对基本方法的调度,完成固定的逻辑)。
为了防止恶意的操作,一般模板方法上都添加上final关键字,不允许被覆写。
在这里插入图片描述
在这里插入图片描述

ps.可以提取子类的公共部分代码放入抽象类作为一个普通方法,便于维护

观察者模式

定义:对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新。
关键:(具体被观察者)类中有一个 ArrayList 存放观察者们
在这里插入图片描述
Observer类是抽象观察者,为所有的具体观察者定义一个接口,在得到主题的通知时更新自己
在这里插入图片描述

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值