设计模式学习笔记

设计原则:

开闭原则:对扩展开放,对修改关闭。实际过程中总是难以避免修改,如果非要修改的话修改顶层比修改底层好(后面这句是自己的理解)

依赖倒转原则:高模块不应该依赖低模块,两个都应该依赖抽象。抽象不应该依赖细节,细节应该依赖抽象

单一职责原则:一个类应该仅有一个引起它变化的原因(只干一件事?)

迪米特法则:尽可能降低类成员的访问权限,访问权限越低,和其他类之前的耦合程度越低

优先使用对象的合成/聚合,而不是继承。只有满足is-a关系的对象才应该使用继承

-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

状态机模式:

在状态对象里把操作函数写好,然后把状态对象给到context对象,当执行context对象的操作的时候,就去调用context里的状态对象的操作

策略模式和状态机模式极为相似,区别在于状态机模式可以自动转换状态,例如本来context是success状态(持有successStateMachine),context执行success后是调用successStateMachine的success后再把context的状态机换成failStateMachine

个人的理解状态机的优点:

如果不把各个状态对应的操作拆到状态机里,来一个状态要做操作的时候,要有很多if else或者switch来判断是啥状态,随着状态越来越多,分支也越来越多,分支越多代码可读性越差,越难维护。

-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

建造者模式:

abstract class 车builder {

    public 造轮子();

    public 造发动机();

    public 得到车();

}

class 轿车builder extends 车builder {

    车 car = new 轿车();

    public 造轮子() {

        car.轮子 = 小轮子

    }

    public 造发动机() {

        car.发动机 = 小马力发动机

    }

    public 得到车() {

        return car;

    }

}

class 卡车builder extends 车builder {

    车 car = new 卡车();

    public 造轮子() {

        car.轮子 = 大轮子

    }

    public 造发动机() {

        car.发动机 = 大马力发动机

    }

    public 得到车() {

        return car;

    }

}

class Director {

    public 造车(车builder) {

        车builder.造轮子;

        车builder.造发动机;

        车builder.得到车;

    }

}

业务类 {

    车builder builder = new 卡车builder();

    Director director = new Director();

    车 car = director.造车(builder);

}

builder作为抽象类规定了建造产品都有哪些步骤

建造具体产品的builder(下面叫做realBuilder)里面实现建造产品的各个步骤的具体的操作。director调realBuilder的建造步骤,最终构造好产品。用户创建director,再创建realBuilder,把realBuilder传到director里,就能创建产品了。相当于建造不同的产品,建造的步骤有哪些、先后顺序都是一样的(都放在director里),只是不同产品具体的步骤实现是不一样的(在realBuilder实现)

https://www.jianshu.com/p/3d1c9ffb0a28

-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

访问者模式:

基础类(被访问者)里面留出一个接口,这个接口用来传入访问者。这个接口在传入访问者之后,又调了访问者的方法并把自己(被访问者)传进去(this),然后访问者的方法里就可以对被访问者做各种处理。

访问者都实现同一个接口,这个接口里定义了几个对不同的访问者的处理方法

访问者模式的适用场景是程序的数据结构一般不变化、比较稳定,但是处理数据结构的算法经常变化的情景。因为访问者模式的优点就在于把对数据的处理抽出来成为了访问者,再想增加新的算法(处理方式)的时候,只需要再写一个访问者,然后客户端把新访问者传到数据结构(被访问者)里就行了。

https://www.runoob.com/design-pattern/visitor-pattern.html

其实有个疑问,直接在客户端里把数据结构对象传到算法对象的接口不就行了,为啥还要数据结构类提供一个接口,然后这个接口里再调算法的接口,然后客户端去调数据结构的接口。脱了裤子放屁?

-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

简单工厂模式:不同的类(“产品”)继承自同一个类,然后在工厂类里,根据不同的条件,创建不同的字类(“产品”)并当成父类的类型返回(利用多态)。业务类持有工厂,创建“产品”,用产品来实现业务逻辑

abstract class Animal {

    void eat();

}

class Dog extends Animal {

    void eat() {

        狗吃骨头

    }

}

class Cat extends Animal {

    void eat() {

        猫吃鱼

    }

}

class Factory {

    Animal getAnimal(animalNo) {

        switch(animalNo) {

             case 1:

             return new Dog();

             case 2:

             return new Cat();

        }

    }

}

class 业务类 {

    Factory factory = new Factory();

    Animal animal = factory.getAnimal(1);

}

-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

工厂模式:给每个产品创建一个工厂。跟简单工厂相比,简单工厂是在工厂里判断创建哪个产品,而工厂模式实在业务类里判断需要用哪个工厂来创建对应的产品

abstract class Animal {

    void eat();

}

class Dog extends Animal {

    void eat() {

        狗吃骨头

    }

}

class Cat extends Animal {

    void eat() {

        猫吃鱼

    }

}

abstract class Factory {

    Animal getAnimal(animalNo);

}

class DogFactory extends Factory {

    Animal getAnimal() {

        return new Dog();

    }

}

class CatFactory extends Factory {

    Animal getAnimal() {

        return new Cat();

    }

}

class 业务类 {

    Factory factory = new DogFactory();

    Animal animal = factory.getAnimal();

}

-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

抽象工厂:如果有多个产品族的情况下,可以考虑用一用。不过也有弊端:如果增加产品族的情况下还比较好,例如增加半野生半家养产品族,只需要增加半野生半家养猫、半野生半家养狗、半野生半家养工厂就行,满足了开闭原则(面向扩展开放、面向修改关闭)。但是如果增加一个产品,例如兔子,那么除了增加兔、家养兔、野生兔之外还需要修改工厂、家养工厂、野生工厂,增加生产兔子接口,这就需要修改好几个类,不满足开闭原则。所以要根据实际情况选择。

-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

策略模式:跟简单工厂的思路差不多,几个策略类继承自同一个父类,然后把策略类放进context里,当需要执行策略的时候,业务类调context,context调策略类的实现方法。

可以在业务类里把策略类创建好然后传给context;也可以把context当成简单工厂模式里的工厂,在context里根据需要的不同的策略创建不通的策略类并保存起来。如果采用第二种创建策略类的方法,那么就和简单工厂模式过于相似,我自己理解的区别在于简单工厂模式需要业务类自己持有工厂和“产品”,而策略模式只需要持有context就行了,对业务类隐藏了创建工厂类这一步,并且业务不感知产品类了

-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

装饰模式没太看明白,后面再看下吧,先学习别的模式

-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

代理模式:

interface Operation{

    public void handle();

}

class RealOperation implements Operation{

    public void handle() {

        搞事情

    }

}

class Proxy implements Operation {

    RealOperation realOperation = new RealOperation();

    public void handle() {

        realOperation.handle();

    }

}

Proxy和RealOperation 都实现了同一个接口,Proxy对接口的实现方法就是调用RealOperation的同样的方法,所以想要调用RealOperation的什么方法,直接去调用Proxy的同样的方法就行了,就把对RealOperation的操作交给Proxy来代理做了。

我想到的代理模式的一个好处:比如收学费、收书本费、收住宿费分别是三个类,现在决定在收费(调用这三个类)之前先签名,如果不用代理,就需要把三各类都修改一下,加上签名的步骤。如果用代理来做的话,收费的时候用代理类,代理类再调用具体的实现类的方法,那么只需要在代理类调用具体类的实现方法之前加上签名的步骤就好了

-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

原型模式:

用来创建多个一样的对象的模式。首先用正常方式创建一个对象作为原型,然后用这个原型通过clone()来再创建多个对象。需要注意的是clone()做的是浅拷贝

浅拷贝:从A对象clone出一个B,值类型正常从A复制到B,但是引用类型只是把引用(指针)复制到B,引用指向的内存还是同一份

深拷贝:对于A的引用类型,B会复制出一份新的内存,把新内存的引用给B。注意如果是引用的引用,那就还是仅复制指针

详见https://blog.youkuaiyun.com/zhangjg_blog/article/details/18369201

-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

模板方法模式:

把公共的行为抽象到父类中作为模板,字类继承模板类,并实现不同的细节

上面的是C#代码

-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

外观模式:

把多个子系统(类)的操作整合在一个新的类里,就是外观模式了。

上面的是C#代码

-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

观察者模式

当一个对象(通知者)的改变会引起一串其他对象(观察者)的改变时,可以使用观察者模式。就是把一堆观察者(实现了同一个接口)放到通知者里面,通知者发生状态改变的时候,挨个调这些观察者实现的接口方法。这群观察者需要持有通知者对象(或者在构造函数传进去,或者在实现的接口里传进去等),这样才能知道当前通知者的状态是啥。观察者和通知者应该都继承抽象类/实现接口,这样才能互相不依赖于具体的类,而依赖于抽象,体现了依赖倒转原则

上面的是C#代码

但是这个观察者模式有这几个缺点:1、观察者都必须继承一个父类或者实现一个接口,否则通知者没法忽略具体类型利用多态通知各个观察者。2、各个观察者响应通知者的操作都必须放在同一个函数里(继承自父类的函数或者实现的接口),而实际上有可能不同的观察者响应通知的函数是不同的

而委托机制可以解决上述的两个问题:

java是用反射来实现委托机制的

就是把各个观察者对象转换成Object类型,然后和观察者响应通知的函数和参数一起放到一个类里

class Event{

    Object observer; //观察者

    String methodName; // 响应函数

    Object[] parms;  //响应函数的参数

        Class[] paramTypes; //响应函数的参数类型

}

然后把这个event放到通知者里面,当事件发生时通知者取到各个event,通过反射机制调用观察者的响应函数:

Method method=event.observer.getClass().getMethod(this.getMethodName(), this.getParamTypes());

method.invoke(event.observer, event.parms);

-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

适配器模式:A类的接口是我想要用的,但是那个接口我没法直接调(也别管为啥没法直接调了),然后我写一个B类,在B类的接口里调A类的接口,然后我调B类的接口

-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值