首页 > 其他分享 >[设计模式 1] 设计模式笔记(大话设计模式总结)

[设计模式 1] 设计模式笔记(大话设计模式总结)

时间:2024-06-07 17:36:04浏览次数:13  
标签:大话 笔记 public class 抽象 模式 设计模式 方法 void

设计模式总结 (java版 1)


1. 简单工厂模式

需求: 设计一个计算器, 有一个抽象的运算类,他里边有两个数字属性和一个getResult()抽象方法,这个类被四个加减乘除的具体的算法类继承,然后有一个简单工厂类,这个简称工厂类是用来生成一个具体的运算类的,然后就在简单工厂类里有一个逻辑的判断,这个逻辑的判断会让简单工厂生成对应的具体类, 然后调用这个具体的类的getResult()方法就可以了.

抽象一个运算类

@Data
public abstract class Operation {
    public Double numberA;
    public Double numberB;

    public abstract Double getResult();
}

有一个加法和减法的类来继承这个运算类

public class SubOperation extends Operation {
    @Override
    public Double getResult() {
        Double result = 0.0;
        result = numberA - numberB;
        return result;
    }
}
public class AddOperation extends Operation {
    @Override
    public Double getResult() {
        Double result = 0.0;
        result = numberA + numberB;
        return result;
    }
}

简单工厂用来判断产生哪种具体类型的运算类

public class SimpleFactory {

    public static Operation createOperation(String type) {
        Operation operation = null;
        if ("add".equals(type)) {
            operation = new AddOperation();
        }
        if ("sub".equals(type)) {
            operation = new SubOperation();
        }
        return operation;
    }
}

主函数 通过给简单工厂传入type来产生具体的运算类,并调用getResult方法获取结果

public class Client {
    public static void main(String[] args) {
        Operation operation = SimpleFactory.createOperation("add");
        operation.numberB = 10.0;
        operation.numberA = 5.0;
        Double result = operation.getResult();
        System.out.println(result);
    }
}

需要注意这里的细节: 作为客户端的调用, 这里不仅要知道简单工厂这个类, 而且还需要调用operation的一个方法, 所以调用需要了解两个类;

2. 策略模式

如果一个商场需要一个收银软件,有不同的折扣方式, 比如满减, 比如打折; 这是不同的策略;也就相当于简单工厂模式里不同的operation,但是, 简单工厂模式在于调用者需要知道工厂类, 页需要知道具体的Operation类的getResult()方法, 所以, 策略模式下, 可以把上述的例子改成这样:

工厂类新增一个Operation对象, 并新增一个getResult()类, 用来调用Operation的getResult()方法

public class SimpleFactory {

    public Operation operation;

    public createOperation(String type) {
        Operation operation = null;
        if ("add".equals(type)) {
            this.operation = new AddOperation();
        }
        if ("sub".equals(type)) {
            this.operation = new SubOperation();
        }
    }

    public double getResult() {
        return operation.getResult();    
    }
}
public class Client {
    public static void main(String[] args) {
        Double result = SimpleFactory.createOperation("add").getResult();
        System.out.println(result);
    }
}

(getResult()方法需要调整一下, 但主要思想就是, 在简单工厂中去集成调用Operation的getResult()方法。

3. 装饰模式

装饰模式是这样的,当一个人需要有很多的衣服去穿搭,然后我们要在命令行中展示出这个人的姓名,然后他所穿的各种衣服

这个时候我们可以设计一个person类:

  • 有一个show用来展示名字

然后有一个抽象的服饰类:

  • 有一个field是人,

  • 有一个装饰方法用来初始化自己的field,

  • 有一个show方法, 如果filed不为空, 调用filed的show方法;

然后有一堆各种各样的服饰去继承这个抽象的服饰类,

  • 每一个服饰类都要重写show方法, 受方法中,首先自定义自己要打印的东西, 然后去调用base.show(), 既自己的field的show方法;

Person:

@Data
public class Person {

    private String name;

    public void show() {
        System.out.println("装扮的人: " + name);
    }
}

Finery: 服饰类

public class Finery extends Person {

    private Person person;

    public void decorate(Person person) {
        this.person = person;//重点
    }

    @Override
    public void show() {
        if (person != null) {
            person.show();
        }
    }
}

具体的各种类:

public class TShirt extends Finery {

    @Override
    public void show() {
        System.out.println("T恤");
        super.show();//重点
    }
}

主方法的调用:

Person xiaoCai = new Person("小菜");
TShirt tShirt = new TShirt();
Hat hat = new Hat();


tShirt.decorate(xiaoCai);
hat.decorate(tShirt);
hat.show();

装饰模式主要是可以动态的去添加装饰模式,主要是可以动态的去添加各种装饰,

也就是说, 在建造的过程中是不稳定的, 这是和建造者的主要区别。

4. 代理模式

别人代理你做事情

(例子: 帮别人送东西)

抽象的subject:

public abstract class Subject {
    public abstract void request();
}

真实的subject

public class RealSubject extends Subject {
    @Override
    public void request() {
        System.out.println("真实主题类的执行方法");
    }
}

代理类:

public class Proxy extends Subject {
    private RealSubject realSubject;

    @Override
    public void request() {
        if (this.realSubject == null) {
            this.realSubject = new RealSubject();
        }
        this.realSubject.request();
    }
}

主函数:

public class Client {
    public static void main(String[] args) {
        Subject proxy = new Proxy();
        proxy.request();
    }
}

5. 工厂方法模式

每一个operation都又对应的工厂来产生

因为简单工厂模式其实违背了开放封闭原则,在需要新加一个运算类的时候, 需要修改简单工厂的方法,用来判断去生成哪种运算类, 而工厂方法模式 则遵循了开放封闭原则, 在需要添加一个新的运算类的时候,需要添加一个新的运算工厂类, 然后再添加一个新的运算类就可以了。

6. 原型模式

用原型实例指定创建对象的种类, 并通过拷贝这些原型创建新的对象;

简单来说就是通过克隆一个对象来创建另一个对象, 不过在java中涉及到深拷贝和浅拷贝到问题

7. 模版方法模式

模板方法模式主要是用来定义怎样把一堆方法用模板的方式来处理的模式, 也就是说,抽象类中有两个抽象方法,然后还有一个方法是用模板的方式来调用这两个抽象方法的, 而这两个抽象方法则由具体的类分别去实现不同的细节, 但是这个模板方法给出了逻辑的骨架,然后去调用这两个抽象方法的操作来实现细节的方法。

上图中的抽象内装有一个模板方法,这个模板方法中会调用抽象的操作, 而具体的那去实现这两个抽象的方法。

8. 外观模式

非常无聊, 类似买基金, 基金其实是多只股票的买入买出, 只暴露一个调用出来。

9. 建造者模式(生成器模式)

将一个复杂对象的构建, 和他的表示分离, 是的同样的构建过程可以创建不同的表示

以建造一个小人为例, 我要创建一个高的人,我要创建一个矮的人, 我需要让创建人这个过程是稳定的,不能缺胳膊少腿。

所以我要做的是抽象一个PersonBuilder, 里面有一个画笔属性, 然后有创建头, 手, 腿, 脚的各种抽象方法,

然后有 俩个具体的创建高或者矮的人的类, 分别去实现各种创建头手脚腿的抽象方法。

这个时候我们需要一个指挥者, 指挥者有一个PersonBuilder的属性, 同时有一个方法 来按照顺序固定的创建头手腿脚, 这样我们创建的人就不会有缺胳膊少腿的情况了, 保证了建造的稳定。

PersonBuilder:

@Data
public abstract class PersonBuilder {

    private String pen;
    public abstract void BuildHead();
    public abstract void BuildBody();
    public abstract void BuildArm();
    public abstract void BuilderLeg();
}

TallPersonBuilder

public class TallPersonBuilder extends PersonBuilder {
    @Override
    public void BuildHead() {
        System.out.println("具体的建造一个高一点人的头");
    }
    @Override
    public void BuildBody() {
        System.out.println("具体的建造一个高一点人的身体");
    }
    @Override
    public void BuildArm() {}
    @Override
    public void BuilderLeg() {}
}

personDirector

public class PersonDirector {
    private PersonBuilder personBuilder;
    public PersonDirector(PersonBuilder personBuilder) {
        this.personBuilder = personBuilder;
    }
    public void CreatePerson() {
        personBuilder.BuildHead();
        personBuilder.BuildBody();
        personBuilder.BuildArm();
        personBuilder.BuilderLeg();
    }
}

Client:

public class Client {
    public static void main(String[] args) {
        PersonBuilder personBuilder = new TallPersonBuilder();
        PersonDirector personDirector = new PersonDirector(personBuilder);
        personDirector.CreatePerson();
    }
}

如果是具体的产品的话, 可以在建造者中添加一个抽象方法来返回该产品。

10. 观察者模式

subject用来通知, observer用来观察

总的来说就是subject中 有一个observer的list, 在subject中有一个方法用来通知这个list中的每一个, 调用每一个observer的update方法来通知observer要去做什么

observer中也要有一个属性subject, 在update的方法中需要用到subject的状态

问题是在subject中有observer这个field, 在observer中也有subject这个field,更大的问题是,不同的observer中的update方法名必须是相同的, 双重的耦合;

解决方法: 事件委托

委托就是一种引用方法的类型(其实就是封装一下要update的方法, 给这个update方法规定一个确定的参数和返回值)具体的使用方式可以查看[ Spring事件发布与监听 ] - Roy2048 - 博客园

11. 抽象工厂模式

抽象工厂模式:

举个例子, 数据库中有两张表, User和Department, 但是要实现用不同的数据库的连接来对这两张表进行增加和查询的操作, 就相当于, 有两种抽象产品, 然后要去生产这两种产品, 但是会用到不同的工厂。 也就是一个抽象工厂是可以生产两种产品的, 但这两种产品又属于不同的类型。

既, 如果只有一张表User, 则其实是工厂方法模式, 而有多张表的时候,就变成了抽象工厂模式。

缺点: 如果要增加一张表, 则在sqlServerFactory, AccessFactory, IFactory都要添加相应的方法, 并添加一个新的具体表接口。

改进方法:

1 简单工厂模式

先使用简单工厂去实现, 既, 在一个简单工厂DataAccess中有两个方法, 用字符串判断哪个数据库, 然后生成相关的数据库操作类,

2 用反射来替换switch判断

代码中, 用Assembly.Load().CreateInstance("具体数据库类")来生成, 然后把这个字符串抽取成变量, 但是依然需要在代码中来指定变量的。

3 用反射+配置文件来实现

读取配置, 然后在代码中切换。

12. 状态模式

状态模式主要解决的是当控制一个对象状态转换的条件表达式过于复杂时的情况。把状态的判断逻辑转移到表示不同状态的一系列类当中,可以把复杂的判断逻辑简化。当然,如果这个状态判断很简单,那就没必要用‘状态模式’了。

本来是在一个主函数中去switch判断, 下一步应该怎么办;而状态模式是在每一个具体的状态类中去判断下一步应该做什么。 相当于把主函数中的switch分散到每个状态中。

13. 适配器模式

target接口是客户所期待或者一直在使用的接口

现在要使用adaptee的方法, 需要adapter继承target, 并有一个私有属性adaptee, 在继承的target的方法中调用adaptee的方法,

对外表现为, 依然使用target对象, 但使用到了adaptee的方法。这用模式通常不在设计一个新系统时使用,而在对接或者维护的时候使用。

Target:

public class Target {
    public void request() {
        System.out.println("Target: The default target's behavior.");
    }
}

Adaptee:

public class Adaptee {
    public void specificRequest() {
        System.out.println("Adaptee: I can work just fine!");
    }
}

Adapter:

@Data
public class Adapter extends Target {
    private Adaptee adaptee;
    @Override
    public void request() {
        adaptee.specificRequest();
    }
}

client:

public class Client {
    public static void main(String[] args) {
        Target target = new Adapter();
        target.request();//client依然使用target的方法
    }
}

14. 备忘录模式(没用)

15. 组合模式

组合模式将个体和整体以树的形式结合起来, 比如要创建一个树, 可以创建一个抽象的节点, 这个节点可以被叶节点(无法再添加节点), 和枝节点, 可以继续添加, 也就是所有的节点都继承抽象节点, 在枝节点中可以添加一个list用于存储其他的枝节点或者叶节点。具体可以看python版本的例子。设计模式

16. 迭代器模式

继承基本的迭代接口就可以了(循环遍历)

17. 单例模式

单例模式(Singleton),保证一个类仅有一个实例,并提供个访问它的全局访问点。

public class Singleton {
    private static volatile Singleton singleton;//volatile 防止指令重排序, 保证有序性和可见性
    private Singleton(){}
    public Singleton getInstance() {//双重检查加锁
        if (singleton == null) {
            synchronized (Singleton.class) {//对Singleton.class这个类的内存地址锁定进行同步
                //即使Singleton没有被实例化, 这个.class类对象也可以被锁定
                if (singleton == null) {
                    singleton = new Singleton();
                }
            }
        }
        return singleton;
    }
}

volatile关键字作用及原理 - 掘金

Java单例模式的8种写法 - 掘金

18. 桥接模式

这种方式下, 如果新增一个手机品牌或者新增一个软件, 都需要很大的改动(比如修改抽象类, 增加手机品牌, 在之前的品牌下增加软件等, 需要修改很多东西)

所以修改构架为:

然后手机和软件需要联系起来:

先定义一个抽象的MobileSoft类, 然后写MobileGameSoft和MobileMusicSoft的具体类:

public abstract class MobileSoft {
    public abstract  void run();
}

MobileGameSoft

public class MobileGameSoft extends MobileSoft {
    @Override
    public void run() {
        System.out.println("手机游戏软件运行");
    }
}

MobileMusicSoft

public class MobileMusicSoft extends MobileSoft {
    @Override
    public void run() {
        System.out.println("手机音乐软件运行");
    }
}

然后定义手机品牌抽象类, 并有两个具体的品牌来继承:

public abstract class MobileBrand {
    public MobileSoft mobileSoft;
    public void setMobileSoft(MobileSoft mobileSoft) {
        this.mobileSoft = mobileSoft;
    }
    public abstract void run();
}

MobileBrandN:

public class MobileBrandN extends MobileBrand {
    @Override
    public void run() {
        System.out.println("手机品牌N运行");
        mobileSoft.run();
    }
}

MobileBrandM:

public class MobileBrandM extends MobileBrand {
    @Override
    public void run() {
        mobileSoft.run();
    }
}

在客户端的调用:

public class Client {
    public static void main(String[] args) {
        //要在品牌N里使用音乐软件:
        MobileBrandN brandN = new MobileBrandN();
        brandN.setMobileSoft(new MobileGameSoft());
        brandN.run();
    }
}

这样, 就是桥接, 如果新加手机品牌或者软件, 就很方便了。

标签:大话,笔记,public,class,抽象,模式,设计模式,方法,void
From: https://www.cnblogs.com/Roy2048/p/18237582

相关文章

  • Visual Instruction Tuning论文阅读笔记
    Motivation&AbsMotivation:之前基于LLM的通用助手仅能处理文本。数据:使用纯语言的GPT4生成多模态语言-图像指令数据。模型:基于生成数据端到端训练的模型LLaVA,用于通用视觉语言理解。指标:两个benchmark。GPT-assistedVisualInstructionDataGeneration现有的多模态指令数......
  • 点分治 学习笔记
    引入在点分治的过程中,它的遍历顺序会遍历每棵子树的重心,而这棵由重心生成的树会产生一棵新的树,便是点分树。常用来解决树上与树的形态无关的路径问题。过程如下图,它的点分树是它自己。因此可以看出一棵树的点分树可能是它本身。性质因为点分树\(\mathcal{O}(\logn)\)......
  • 不凡学院笔记
    Vue前端性能难题Vue前端性能问题通常涉及到如何优化组件渲染性能,减少不必要的DOM更新,以及处理大量数据的渲染和滚动性能。以下是一些常见的Vue前端性能问题及其解决方案:避免在v-for循环中使用key,除非你明确知道元素的交互方式。解决方案:使用唯一且稳定的ID作为key。避免在模板......
  • 得帆云学习笔记
    数仓规划数仓规划是开发人员对业务的解析、分类和提炼的过程。数仓开发人员需要根据对整体业务的理解来划分出不同业务领域、业务领域下对应的数据域、以及数据域下的业务过程。根据业务的类型或其他特征来划分业务领域。根据该业务下再细分出的类别来划分数据域。根据业务中......
  • 推荐系统三十六式学习笔记:原理篇.内容推荐07|人以群分,你是什么人就看到什么世界
    目录协同过滤基于用户的协同过滤背后的思想原理实践1、构造矩阵2、相似度计算3、推荐计算4、一些改进应用场景:总结谈及推荐系统,不得不说大名鼎鼎的协同过滤。协同过滤的重点在于协同,所谓协同,也就是群体互帮互助,互相支持是群体智慧的体现,协同过滤也是这般简单直接,历......
  • 读书笔记分享
    1.绝大多数父母都是爱孩子的,可他们却不是称职的父母。世界上任何职业都要培训、考核、竞争上岗,唯有“父母”这个职业是没有这些程序,只要生了小孩,就是天经地义的父母。2.由于自身工作特点,“白领”们的部分器官和组织,如脑组织、视觉神经、颈椎等经常处于过度紧张状态,如果不......
  • 进程间通信九天学习笔记
    进程间通信九天学习笔记day1:基本进程操作fork()返回pid进程idgetpid()获取当前进程IDsystem()执行系统命令day2:管道匿名管道pipe(intpipefd[2])pipefd[0]读操作pipefd[1]写操作有名管道(FIFO)mkfifo(,0644)open()read()write()day3:信号标准......
  • 载谭 Binomial Sum 学习笔记
    原文链接:载谭BinomialSum:多项式复合、插值与泰勒展开。下面就从例题开始慢慢说这个算法。P5430[SNOI2017]礼物加强版题目描述给定\(n,k\),求\[n^k+\sum_{i=1}^{n-1}2^{n-1-i}i^k\]答案对\(10^9+7\)取模。\(1\len\le10^{100000},1\lek\le2\times10^7\)。......
  • Golang学习笔记(1):包管理
    Golang学习笔记(1):包管理本人学习Golang主要是为了做MIT6.824的lab,然而一上来就被Golang神奇的import搞混了,因此写一篇博客记录学习Golang的包管理的过程。packagemainimport"fmt"funcmain(){fmt.Println("hello,world")}如果有编程基础肯定会觉得这段代码很好理......
  • 工作笔记(8)
    Program.cs启用OpenAPI支持:(Swagger支持)顶级语句:使用控制器:miniAPIHTTP与HTTPS的区别1.HTTPS协议需要到CA申请证书,一般免费的证书比较少,因而需要一定费用。2.HTTP是超文本传输协议,信息是明文传输,HTTPS则是具有安全性的SSL加密传输协议。3.HTTP和HTTPS使用的是完全不同的链......