设计模式—外观模式(Facade)

目录

一、什么是外观模式?

二、外观模式具有什么优点吗?

三、外观模式具有什么缺点呢?

四、什么时候使用外观模式?

五、代码展示

①、股民炒股代码

②、投资基金代码

③外观模式


思维导图

 

一、什么是外观模式?

为子系统中的一组接口提供一个一致的界面,此模式定义了一个高层接口,这个接口使得这一子系统更加容易使用。

Facade:外观,为多个子系统对外提供一个共同的接口

SubSystem:子系统:实现子系统功能,每一个类表示为一个子系统

Client:客户,通过外观访问各个子系统功能

二、外观模式具有什么优点吗?

降低了子系统与客户端之间的耦合度,使得子系统的变化不会影响调用它的客户类;

三、外观模式具有什么缺点呢?

1.不能很好地限制客户使用子系统类,很容易带来未知风险;

2.增加新的子系统可能需要修改外观类或客户端的源代码,违背了“开闭原则”

四、什么时候使用外观模式?

①、在设计初期阶段,应该要有意识的将不同的两个层分离,比如经典的三层架构,就需要考虑在数据访问层和业务逻辑层、业务逻辑层和表示层的层与层之间建立外观的Facade,这样可以为复杂的子系统提供一个简单的接口,使得耦合大大降低。

②、在开发阶段,子系统往往因为不断地重构演化而变得越来越复杂,大多数的模式使得使用时也都会产生很多很小的类,这本是好事,但也给外部调用它们的用户程序带来了使用上的困难,增加外观Facade可以提供一个简单的接口,减少它们之间的依赖。

③、在维护一个遗留的大型系统时,可能这个系统已经非常难以维护和扩展了,但因为它包含非常重要的功能,新的需求开发必须要依赖于它。


五、代码展示

场景:越来越多的人都在炒股票,行情很火, 但许多人进入这个行业只是盲目跟风,并不是足够了解证券知识,对于这个行业并不熟悉。如果是你自己单独去买股票的话需要了解每支股票具体的细节,如果要买十股的话就需要了解是个,这样非常麻烦。这个时候你就会想如果有一个帮手来帮助你管理股票的话就好了!基金就可以作为你的帮手,它把投资者分散的资金集中起来,交给专业的经理人进行管理,投资于股票、债券、外汇等领域,而基金投资的收益归持有投资者所有,管理机构只是收取一定比例的托管管理费用。你不需要了解股票具体是什么时候买和卖合适,你只需要把钱给基金,基金帮你买了这十股。

①、股民炒股代码

股票类

//股票1
class Stock1
{
        //卖股票
        public void Sell()
        {
            Console.WriteLine(" 股票1卖出");
        }

        //买股票
        public void Buy()
        {
            Console.WriteLine(" 股票1买入");
        }
}

//股票2
class Stock2
{
        //卖股票
        public void Sell()
        {
            Console.WriteLine(" 股票2卖出");
        }

        //买股票
        public void Buy()
        {
            Console.WriteLine(" 股票2买入");
        }
}

// 股票3
class Stock3
{
        //卖股票
        public void Sell()
        {
            Console.WriteLine(" 股票3卖出");
        }

        //买股票
        public void Buy()
        {
            Console.WriteLine(" 股票3买入");
        }
}

//国债1
class NationalDebt1
{
        //卖股票
        public void Sell()
        {
            Console.WriteLine(" 国债1卖出");
        }

        //买股票
        public void Buy()
        {
            Console.WriteLine(" 国债1买入");
        }
}

// 房地产1
class Realty1
{
        //卖股票
        public void Sell()
        {
            Console.WriteLine(" 房地产1卖出");
        }

        //买股票
        public void Buy()
        {
            Console.WriteLine(" 房地产1买入");
        }
}

客户端

static void Main(string[] args)
{
            Stock1 gu1 = new Stock1();       //关联关系:Stock1 gu1 =null; gu1 = new Stock1();
            Stock2 gu2 = new Stock2();
            Stock3 gu3 = new Stock3();
            NationalDebt1 nd1 = new NationalDebt1();
            Realty1 rt1 = new Realty1();

            gu1.Buy();
            gu2.Buy();
            gu3.Buy();
            nd1.Buy();
            rt1.Buy();

            gu1.Sell();
            gu2.Sell();
            gu3.Sell();
            nd1.Sell();
            rt1.Sell();

            Console.ReadKey();
}

这样的话用户需要了解股票、国债、房产情况,需要参与这些项目的具体买和卖。耦合性很高。我们可以增加基金类。

②、投资基金代码

基金类

//基金类
class Fund
{
        //成员变量
        Stock1 gu1;
        Stock2 gu2;
        Stock3 gu3;
        NationalDebt1 nd1;
        Realty1 rt1;

        //基金类,它需要了解所有的股票或其他投资方式的方法或属性,进行组合,以备外界调用
        //此处同原型模式有异曲同工之处,在实例化本类的同时实例化相应的子类
        public Fund()              //构造方法
        {
            gu1 = new Stock1();         //实例化股票1
            gu2 = new Stock2();         //实例化股票2
            gu3 = new Stock3();         //实例化股票3
            nd1 = new NationalDebt1();  //实例化国债1
            rt1 = new Realty1();        //实例化房地产1
        }

        public void BuyFund()        //买
        {
            gu1.Buy();
            gu2.Buy();
            gu3.Buy();
            nd1.Buy();
            rt1.Buy();
        }

        public void SellFund()          //卖
        {
            gu1.Sell();
            gu2.Sell();
            gu3.Sell();
            nd1.Sell();
            rt1.Sell();
        }
}


//股票1
class Stock1
{
        //卖股票
        public void Sell()
        {
            Console.WriteLine(" 股票1卖出");
        }

        //买股票
        public void Buy()
        {
            Console.WriteLine(" 股票1买入");
        }
}

//股票2
class Stock2
{
        //卖股票
        public void Sell()
        {
            Console.WriteLine(" 股票2卖出");
        }

        //买股票
        public void Buy()
        {
            Console.WriteLine(" 股票2买入");
        }
}

//股票3
class Stock3
{
        //卖股票
        public void Sell()
        {
            Console.WriteLine(" 股票3卖出");
        }

        //买股票
        public void Buy()
        {
            Console.WriteLine(" 股票3买入");
        }
}

//国债1
class NationalDebt1
{
        //卖股票
        public void Sell()
        {
            Console.WriteLine(" 国债1卖出");
        }

        //买股票
        public void Buy()
        {
            Console.WriteLine(" 国债1买入");
        }
}

房地产1
class Realty1
{
        //卖股票
        public void Sell()
        {
            Console.WriteLine(" 房地产1卖出");
        }

        //买股票
        public void Buy()
        {
            Console.WriteLine(" 房地产1买入");
        }
}

客户端

static void Main(string[] args)
{ 
            Fund jijin = new Fund();   //实例化基金类
            jijin.BuyFund();           //调用买的方法
            jijin.SellFund();           //调用卖的方法

            //此时用户不需要了解股票,甚至可以对股票一无所知,买了基金就回家睡觉
            //一段时间后再赎回就可以大把数钱。


            Console.ReadKey();          //等待用户按下任意键退出
}

这样写的好处是什么?外部不需要知道基金怎么组合的、具体细节,这样就大大降低应用程序复杂度,提高程序可维护性

与其它模式的联系:

基金类中的构造方法和原型模式很类似,客户端在实例化原型对象的时候,同时实例化具体的原型类

基金类中的买和卖的方法和建造者模式中的指挥者类的思想异曲同工之处,客户端提出要建造一个瘦人类告诉指挥者,指挥者指挥工人建造出小人,最后把建造好的小人展示给客户。

③外观模式

//四个子系统类
class SubSystemOne
{
        public void MethodOne()
        {
            Console.WriteLine("子系统方法一");
        }
}

class SubSystemTwo
{
        public void MethodTwo()
        {
            Console.WriteLine("子系统方法二");
        }
}

class SubSystemThree
{
        public void MethodThree()
        {
            Console.WriteLine("子系统方法三");
        }
}

class SubSystemFour
{
        public void MethodFour()
        {
            Console.WriteLine("子系统方法四");
        }
}





//外观类,他需要了解所有的子系统的方法或属性,进行组合,以备外界调用
class Facade
{
        SubSystemOne one;
        SubSystemTwo two;
        SubSystemThree three;
        SubSystemFour four;

        public Facade()
        {
            one = new SubSystemOne();
            two = new SubSystemTwo();
            three = new SubSystemThree();
            four = new SubSystemFour();
        }

        public void MethodA()
        {
            Console.WriteLine("\n方法组A() -----");
            one.MethodOne();
            two.MethodTwo();
            three.MethodThree();
            four.MethodFour();
        }

        public void MethodB()
        {
            Console.WriteLine("\n方法组B()----");
            two.MethodTwo();
            three.MethodThree();
        }
} 

涉及到的知识

①、构造方法

又叫构造函数。

目的:对类进行初始化。

特点:与类同名,没有返回值,不需要void,在new时候调用。

所有类都有构造方法,如果你不编码则系统默认生成空的构造方法,若你有定义的构造方法,那么默认的构造方法就会失效了

形式:比方说有一个猫出生下来就叫点点,Cat cat = new Cat("点点");

②、修饰符

public:共有的,所有的类都可以访问,

internal:同一项目的可以访问,类默认是这个

private:私有的,只允许同一类中的成员访问,子类都不可访问,成员默认是这个

protected:保护的,只有子类可以访问

③、字段、属性

字段:程序开发中常见的常量或变量,它是类的一个构成部分,它使得类和结构可以封装数据。默认private,只允许本类可以访问,客户端不可以访问

属性:是一个方法或一对方法。默认public,有get和set两个方法

get访问器返回与声明的属性相同的数据类型,表示的意思是调用时可以得到内部字段的值或引用;

set访问器没有显式设置参数,但它有一个隐式参数,用关键字value表示,它的作用是调用属性时可以给内部的字段或赋值。

为什么要使用get和set?

由于属性中可以包含大量的语句,因此可以对赋予的值进行检查,如果值不安全或者不符合要求,就可以进行提示,这样就可以避免因为给属性设置了错误的值而导致的错误

private int age;
public int Aget
{
	get{return age;}
    set{
    	if(value<0 && value>100)
        {
        	Console.WriteLine("输入的不合理!");
        }
        else
        {
        	age =value;
        }
}
    

④、封装

每个对象都包含它能进行操作所需要的所有信息,这个特性称为封装,因此对象不必依赖其他对象来完成自己的操作。

有什么好处?

  • 良好的封装能够减少耦合;
  • 类内部的实现可以自由地修改;
  • 类具有清晰的对外接口。

⑤、六大关系

关联(Association):对于两个相对独立的对象,当一个对象的实例与另一个对象的一些特定实例存在固定的对应关系时,这两个对象之间为关联关系。

实现:成员变量

图形:实线+箭头

class Student
{
    public School school;
    public School(){}
}

clss School
{
	public School(){}
}

聚合(Aggregation):整体和个体,个体可以脱离整体而独立存在。

实现:成员变量、构造方法的参数

图形:实线+空心菱形

 

⑥、六大原则

迪米特法则

如果两个类不必彼此直接通信,那么这两个类就不应当发生直接的相互作用。如果其中一个类需要调用另一个类的某一个方法的话,可以通过第三者转发这个调用。

依赖倒转原则

-高层模块不应该依赖底层模块。两个都应该依赖抽象(接口/抽象类)。

-抽象不应该依赖细节(具体类)。细节应该依赖抽象。

无论主板、CPU、内存、硬盘都是在针对接口设计的。CPU作为主板上一个可移动的、可扩展的部分,在设计主板的时候只需要把接口定义好,内部再复杂我也不让外界知道,而主板只需要预留与CPU阵脚的插槽就可以了。内存、硬盘、显卡都是如此,哪部分坏了直接更换那部分就行了,而不会导致整个主板全部都要换。

 

依赖倒转其实可以说是面向对象设计的标准

开闭原则

多扩展开放,对修改关闭。

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/102647.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

基于JavaWeb和mysql实现校园订餐前后台管理系统(源码+数据库)

一、项目简介 本项目是一套基于JavaWeb和mysql实现网上书城前后端管理系统&#xff0c;主要针对计算机相关专业的正在做毕设的学生与需要项目实战练习的Java学习者。 包含&#xff1a;项目源码、项目文档、数据库脚本等&#xff0c;该项目附带全部源码可作为毕设使用。 项目都…

python conda实践 sanic框架gitee webhook实践

import subprocess import hmac import hashlib import base64 from sanic.response import text from sanic import Blueprint from git import Repo# 路由蓝图 hook_blue Blueprint(hook_blue)hook_blue.route(/hook/kaifa, methods["POST"]) async def kaifa(req…

使用栈检查括号的合法性 C 实现

使用栈检查括号的合法性 思路讲解&#xff1a;首先从数组数组0下标开始&#xff0c;如果是左括号直接无脑压入栈&#xff0c;直到出现右括号开始判断合法与否。遇到右括号分两种情况&#xff0c;第一种是空栈的情况&#xff0c;也就是说我们第一个字符就是右括号&#xff0c;那…

ShardingSphere——弹性伸缩原理

摘要 支持自定义分片算法&#xff0c;减少数据伸缩及迁移时的业务影响&#xff0c;提供一站式的通用弹性伸缩解决方案&#xff0c;是 Apache ShardingSphere 弹性伸缩的主要设计目标。对于使用单数据库运行的系统来说&#xff0c;如何安全简单地将数据迁移至水平分片的数据库上…

shiro550漏洞分析

准备工作 启动该项目 可以看到没有登录时候&#xff0c;cookie中没有rememberme字段 登录时候 当账号密码输入正确时候 登录后存在该字段 shiro特征&#xff1a; 未登陆的情况下&#xff0c;请求包的cookie中没有rememberMe字段&#xff0c;返回包set-Cookie⾥也没有del…

Java-Optional类

概述 Optional是JAVA 8引入的一个类&#xff0c;用于处理可能为null的值。 利用Optional可以减少代码中if-else的判断逻辑&#xff0c;增加代码的可读性。且可以减少空指针异常的发生&#xff0c;增加代码的安全性。 常用的方法 示例 代码 public class OptionalTest {pub…

Spark有两种常见的提交方式:client 模式和 cluster 模式对机器 CPU 的影响

Spark有两种常见的提交方式&#xff1a;client 模式和 cluster 模式。这两种方式对机器 CPU 的影响略有不同 &#xff0c;请参考以下说明 Client 模式&#xff1a; 在 Client 模式下&#xff0c;Spark Driver 运行在提交任务的客户端节点上&#xff08;即运行 spark-submit 命…

一种改进多旋翼无人机动态仿真的模块化仿真环境研究(Matlab代码实现)

&#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;欢迎来到本博客❤️❤️&#x1f4a5;&#x1f4a5; &#x1f3c6;博主优势&#xff1a;&#x1f31e;&#x1f31e;&#x1f31e;博客内容尽量做到思维缜密&#xff0c;逻辑清晰&#xff0c;为了方便读者。 ⛳️座右铭&a…

Swift 如何从图片数据(Data)检测原图片类型?

功能需求 如果我们之前把图片对应的数据(Data)保持在内存或数据库中,那么怎么从 Data 对象检测出原来图片的类型呢? 如上图所示:我们将 11 张不同类型的图片转换为 Data 数据,然后从 Data 对象正确检测出了原图片类型。 目前,我们的代码可以检测出 jpeg(jpg), tiff,…

实际并行workers数量不等于postgresql.conf中设置的max_parallel_workers_per_gather数量

1 前言 本文件的源码来自PostgreSQL 14.5&#xff0c;其它版本略有不同并行workers并不能显箸提升性能。个人不建议使用并行worker进程&#xff0c;大多数情况下采用postgresql.conf默认配置即可。 PostgreSQL的并行workers是由compute_parallel_worker函数决定的&#xff0c…

无涯教程-Android - AutoCompleteTextView函数

AutoCompleteTextView是一个类似于EditText的视图&#xff0c;只是它在用户键入时自动显示补充数据。 AutoCompleteTextView - 属性 以下是与AutoCompleteTextView控件相关的重要属性。您可以查看Android官方文档以获取属性的完整列表以及可以在运行时更改这些属性的相关方法。…

【人工智能】—_维度灾难、降维、主成分分析PCA、获取旧数据、非线性主成分分析

文章目录 高维数据与维度灾难维度灾难降维为什么需要降维&#xff1f;PRINCIPLE COMPONENT ANALYSIS主成分的几何图像最小化到直线距离的平方和举例主成分的代数推导优化问题计算主成分&#xff08;Principal Components, PCs&#xff09;的主要步骤获取旧数据的方法&#xff1…

ChatGPT插件的优缺点

虽然西弗吉尼亚大学的研究人员看到了最新的官方ChatGPT插件——名为“代码解释器”&#xff08; Code Interpreter&#xff09;的教育应用潜力&#xff0c;但他们也发现&#xff0c;对于使用计算方法处理针对癌症和遗传疾病的定向治疗的生物数据的科学家来说&#xff0c;这款插…

Python钢筋混凝土结构计算.pdf-T001-混凝土强度设计值

以下是使用Python求解上述问题的完整代码&#xff1a; # 输入参数 f_ck 35 # 混凝土的特征抗压强度&#xff08;单位&#xff1a;MPa&#xff09; f_cd 25 # 混凝土的强度设计值&#xff08;单位&#xff1a;MPa&#xff09; # 求解安全系数 gamma_c f_ck / f_cd # …

MySQL分页查询详解:优化大数据集的LIMIT和OFFSET

最近在工作中&#xff0c;我们遇到了一个需求&#xff0c;甲方要求直接从数据库导出一个业务模块中所有使用中的工单信息。为了实现这一目标&#xff0c;我编写了一条SQL查询语句&#xff0c;并请求DBA协助导出数据。尽管工单数量并不多&#xff0c;只有3000多条&#xff0c;但…

[CISCN 2019初赛]Love Math

文章目录 前言考点解题过程 前言 感慨自己实力不够&#xff0c;心浮气躁根本做不来难题。难得这题对我还很有吸引力&#xff0c;也涉及很多知识。只能说我是受益匪浅&#xff0c;总的来说加油吧ctfer。 考点 利用php动态函数的特性利用php中的数学函数实现命令执行利用php7的特…

两个pdf文件合并为一个怎么操作?分享pdf合并操作步骤

不管是初入职场的小白&#xff0c;还是久经职场的高手&#xff0c;都必须深入了解pdf&#xff0c;特别是关于pdf的各种操作&#xff0c;如编辑、合并、压缩等操作&#xff0c;其中合并是这么多操作里面必需懂的技能之一&#xff0c;但是很多人还是不知道两个pdf文件合并为一个怎…

C++------vector【STL】

文章目录 vector的介绍及使用vector的介绍vector的使用 vector的模拟实现 vector的介绍及使用 vector的介绍 1、vector是表示可变大小数组的序列容器。 2、就像数组一样&#xff0c;vector也采用的连续存储空间来存储元素。也就是意味着可以采用下标对vector的元素进行访问和数…

阻塞/非阻塞、同步/异步(网络IO)

1.阻塞/非阻塞、同步/异步(网络IO) 【思考】典型的一次 IO 的两个阶段是什么&#xff1f; 数据就绪 和 数据读写 数据就绪 &#xff1a;根据系统 IO 操作的就绪状态 阻塞 非阻塞 数据读写 &#xff1a;根据应用程序和内核的交互方式 同步 异步 陈硕&#xff1a;在处理 IO …

Docker 常用服务 安装使用 教程

Docker安装常用服务 1、 安装mysql # 1.拉取mysql镜像到本地 docker pull mysql:tag (tag不加默认最新版本) # 2.运行mysql服务 docker run --name mysql -e MYSQL_ROOT_PASSWORDroot -d mysql:tag --没有暴露外部端口外部不能连接 docker run --name mysql -e MYSQL_ROOT_PAS…