【笔记】大话设计模式24-28

news2024/12/25 12:17:46

【笔记】大话设计模式24-28

文章目录

  • 【笔记】大话设计模式24-28
  • 24 职责链模式
      • 24.1 Example
      • 24.2 定义
      • 24.3 Show me the code
      • 24.4 总结
  • 25 中介者模式
      • 25.1 Example
      • 25.2 定义
      • 25.3 Show me the code
      • 25.4 总结
  • 26 享元模式
      • 26.1 Example
      • 26.2 定义
      • 26.3 Show me the code
      • 26.4 总结
  • 27 解释器模式
      • 27.1 Example
      • 27.2 定义
      • 27.3 Show me the code
      • 27.4 总结
  • 28访问者模式
      • 28.1 Example
      • 28.2 定义
      • 28.3 Show me the code
      • 28.4 总结

24 职责链模式

24.1 Example

阿三刚工作时,年底年终奖发的很少,很多大专生拿得比他都多。他只好硬着头皮去找主任说。

主任需要跟部门老总商量一下,能不能提高一下年终奖;部门老总也得要请示公司老总,看能不能加个年终奖;

这种模式就是职责链模式,每个对象都有自己的职责,用户发送一个请求,这个请求经过每个职责对象,只至被处理。

24.2 定义

职责链模式(Chain of Responsibility):使多个对象都有机会处理请求,从而避免请求的发送者和接收者之间的耦合关系。将这个对象连成一条链,并沿着这条链传递该请求,直到有一个对象处理它为止

职责链模式结构图

24.3 Show me the code

class Program
{
    static void Main(string[] args)
    {
        Handler h1 = new ConcreteHandler1();
        Handler h2 = new ConcreteHandler2();
        Handler h3 = new ConcreteHandler3();
        // 设置职责链的上家与下家
        h1.SetSuccessor(h2); 
        h2.SetSuccessor(h3);

        int[] requests = { 2, 5, 14, 22, 18, 3, 27, 20 };
		
        // 循环给最小处理者提交请求,不同的数额,由不同权限处理者处理
        foreach (int request in requests)
        {
            h1.HandleRequest(request);
        }

        Console.Read();

    }
}

// 定义一个处理请示的接口
abstract class Handler
{
    protected Handler successor;
  
	// 设置继任者
    public void SetSuccessor(Handler successor)
    {
        this.successor = successor;
    }
	
    // 处理请求的抽象方法
    public abstract void HandleRequest(int request);
}

// 请求数在0到10之间则有权处理,否则转到下一位
class ConcreteHandler1 : Handler
{
    public override void HandleRequest(int request)
    {
        if (request >= 0 && request < 10)
        {
            Console.WriteLine("{0}  处理请求  {1}",
                              this.GetType().Name, request);
        }
        else if (successor != null)
        {
            successor.HandleRequest(request); // 转移到下一位
        }
    }
}

// 请求数在10到20之间则有权处理,否则转到下一位
class ConcreteHandler2 : Handler
{
    public override void HandleRequest(int request)
    {
        if (request >= 10 && request < 20)
        {
            Console.WriteLine("{0}  处理请求  {1}",
                              this.GetType().Name, request);
        }
        else if (successor != null)
        {
            successor.HandleRequest(request);
        }
    }
}

// 请求数在20到30之间则有权处理,否则转到下一位
class ConcreteHandler3 : Handler
{
    public override void HandleRequest(int request)
    {
        if (request >= 20 && request < 30)
        {
            Console.WriteLine("{0}  处理请求  {1}",
                              this.GetType().Name, request);
        }
        else if (successor != null)
        {
            successor.HandleRequest(request);
        }
    }
}

24.4 总结

  1. 单一职责原则,实现解耦: 接收者和发送者都没有对方的明确信息,且链中的对象自己也并不知道链的结构。

    结果是职责链可简化对象的相互连接,它们仅需保持一个指向其后继者的引用,而不需要保持它所有的候选者的引用。

  2. 开闭原则:可以随时地增加或修改处理一个请求的结构,增强了给对象指派职责的灵活性。

  3. 当需要使用不同方式处理不同种类的请求,并且请求类型和顺序预先未知时,可以使用职责链模式。

    当然,如果处理必须按顺序处理多个处理者时,就可以使用该模式。

25 中介者模式

25.1 Example

阿三现在上班通勤都是使用电动车,很多路口是没有红绿灯的,或者即便有红绿灯,对于电动车驾驶者来说,也是可有可无的存在,没有汽车的时候,他们一般会无视红绿灯,直接通过。但这样会给后面来的汽车带来麻烦,明明是绿灯,他们必须得停下来,导致自己通行受阻。

因此,很多交警每天一大早,站在这些路口,充当一种“中介”,人为地调节电瓶车和汽车之间的通行时间,使得交通秩序处于一种有序状态。

Picture source: Refactoring GURU

25.2 定义

中介者模式(Mediator):用一个中介对象来封装一系列的对象交互。中介者使各对象不需要显式地相互引用,从而使其耦合松散,而且可以对立地改变他们之间的交互。

中介者模式结构图

25.3 Show me the code

来看看模拟的联合国职责的中介者模式代码

class Program
{
    static void Main(string[] args)
    {
        UnitedNationsSecurityCouncil UNSC = new UnitedNationsSecurityCouncil();

        USA c1 = new USA(UNSC);
        Iraq c2 = new Iraq(UNSC);

        UNSC.Colleague1 = c1;
        UNSC.Colleague2 = c2;

        c1.Declare("不准研制核武器,否则要发动战争!");
        c2.Declare("我们没有核武器,也不怕侵略。");

        Console.Read();
    }
}

//联合国机构
abstract class UnitedNations
{
    /// <summary>
    /// 声明
    /// </summary>
    /// <param name="message">声明信息</param>
    /// <param name="colleague">声明国家</param>
    public abstract void Declare(string message, Country colleague);
}

//联合国安全理事会
class UnitedNationsSecurityCouncil : UnitedNations
{
    private USA colleague1;
    private Iraq colleague2;

    public USA Colleague1
    {
        set { colleague1 = value; }
    }

    public Iraq Colleague2
    {
        set { colleague2 = value; }
    }

    public override void Declare(string message, Country colleague)
    {
        if (colleague == colleague1)
        {
            colleague2.GetMessage(message);
        }
        else
        {
            colleague1.GetMessage(message);
        }
    }
}

//国家
abstract class Country
{
    protected UnitedNations mediator;

    public Country(UnitedNations mediator)
    {
        this.mediator = mediator;
    }
}

//美国
class USA : Country
{
    public USA(UnitedNations mediator)
        : base(mediator)
        {
        }
    //声明
    public void Declare(string message)
    {
        mediator.Declare(message, this);
    }
    //获得消息
    public void GetMessage(string message)
    {
        Console.WriteLine("美国获得对方信息:" + message);
    }
}

//伊拉克
class Iraq : Country
{
    public Iraq(UnitedNations mediator)
        : base(mediator)
        {
        }

    //声明
    public void Declare(string message)
    {
        mediator.Declare(message, this);
    }
    //获得消息
    public void GetMessage(string message)
    {
        Console.WriteLine("伊拉克获得对方信息:" + message);
    }

}

25.4 总结

  1. 中介者模式减少了各个Coleague的耦合,使得可以对立地改变和复用各个Colleague类和Mediator
  2. 由于把对象如何协作进行了抽象,将中介作为一个独立的概念并将其封装在一个对象中,这样关注的对象从对象各自本身的行为转移到它们之间的交互上来
  3. 中介者模式一般用于一组对象以定义良好但是复杂的方式进行通信的场合,以及想定制一个分布在多个类中的行为,而又不想生成太多子类的场合。

26 享元模式

26.1 Example

大头以前的有专门做网站的同事。以前的套路就是做水务平台的是一套代码框架,如果有其他城市要做,就把代码搬过来,修改下对应内容和数据库存储路径等,而代码框架是不变的,所以最终会出现每个城市的水务网站看似不同,其实内在的代码框架是一样的,也就是生成了多个网站实例,这是一种资源浪费和冗余。

如何能够将核心代码框架抽离出来,形成独立的代码核心和数据库,通过标识调用不同的数据和页面图标即可,这就是享元模式。

26.2 定义

享元模式(Flyweight):运用共享技术有效地支持大量细粒度的对象。

享元模式结构图

26.3 Show me the code

  1. 基础代码
class Program
{
    static void Main(string[] args)
    {
        int extrinsicstate = 22;

        FlyweightFactory f = new FlyweightFactory();

        Flyweight fx = f.GetFlyweight("Q");
        fx.Operation(--extrinsicstate);

        Flyweight fy = f.GetFlyweight("C");
        fy.Operation(--extrinsicstate);

        Flyweight fz = f.GetFlyweight("J");
        fz.Operation(--extrinsicstate);

        UnsharedConcreteFlyweight uf = new UnsharedConcreteFlyweight();

        uf.Operation(--extrinsicstate);

        Console.Read();
    }
}

// 享元工厂,用来创造并管理Flyweight对象。用来确保合理地共享Flyweight。
class FlyweightFactory
{
    private Hashtable flyweights = new Hashtable();

    public FlyweightFactory()
    {
        flyweights.Add("Q", new ConcreteFlyweight());
        flyweights.Add("J", new ConcreteFlyweight());
        flyweights.Add("J", new ConcreteFlyweight());

    }

    public Flyweight GetFlyweight(string key)
    {
        return ((Flyweight)flyweights[key]);
    }
}

// 接口,通过这个接口,Flyweight可以接受并作用于外部状态
abstract class Flyweight
{
    public abstract void Operation(int extrinsicstate);
}

// 为内部状态增加存储空间
class ConcreteFlyweight : Flyweight
{
    public override void Operation(int extrinsicstate)
    {
        Console.WriteLine("具体Flyweight:" + extrinsicstate);
    }
}

// 指不需要共享的Flyweight子类。Flyweight接口共享成为可能,并不强制共享
class UnsharedConcreteFlyweight : Flyweight
{
    public override void Operation(int extrinsicstate)
    {
        Console.WriteLine("不共享的具体Flyweight:" + extrinsicstate);
    }
}
  1. 网站的享元模式
class Program
{
    static void Main(string[] args)
    {

        WebSiteFactory f = new WebSiteFactory();

        WebSite fx = f.GetWebSiteCategory("产品展示");
        fx.Use(new User("阿三"));

        WebSite fy = f.GetWebSiteCategory("产品展示");
        fy.Use(new User("大头"));

        WebSite fz = f.GetWebSiteCategory("产品展示");
        fz.Use(new User("小豆子"));

        WebSite fl = f.GetWebSiteCategory("博客");
        fl.Use(new User("王五"));

        WebSite fm = f.GetWebSiteCategory("博客");
        fm.Use(new User("钱六"));

        WebSite fn = f.GetWebSiteCategory("博客");
        fn.Use(new User("大批古"));

        Console.WriteLine("得到网站分类总数为 {0}", f.GetWebSiteCount());

        Console.Read();
    }
}

//用户
public class User
{
    private string name;

    public User(string name)
    {
        this.name = name;
    }

    public string Name
    {
        get { return name; }
    }
}


//网站工厂
class WebSiteFactory
{
    private Hashtable flyweights = new Hashtable();

    //获得网站分类
    public WebSite GetWebSiteCategory(string key)
    {
        if (!flyweights.ContainsKey(key))
            flyweights.Add(key, new ConcreteWebSite(key));
        return ((WebSite)flyweights[key]);
    }

    //获得网站分类总数
    public int GetWebSiteCount()
    {
        return flyweights.Count;
    }
}

//网站
abstract class WebSite
{
    public abstract void Use(User user);
}

//具体的网站
class ConcreteWebSite : WebSite
{
    private string name = "";
    public ConcreteWebSite(string name)
    {
        this.name = name;
    }

    public override void Use(User user)
    {
        Console.WriteLine("网站分类:" + name + " 用户:" + user.Name);
    }
}

26.4 总结

如果一个应用程序使用了大量对象,而这些对象造成了很大的存储开销时就应该考虑使用享元模式;

27 解释器模式

27.1 Example

阿三最近喜欢看短视频,有一类挺有意思的。

工作几年的人,想跳槽再正常不过了,不过面试的时候,能不能听懂面试官或单位领导的画外之音,就决定了正常面试的互相理解程度。比如老板说我们这边可以发挥的空间很大,有人就会解释说这里没多少人,需要你干的任务比较多;老板说我们这里工作时间比较自由,有人解释,需要你加班的场景会比较多等等。搞笑的同时,确实和现实有几分相似。

因此,能不能正确解读HR和老板的话语,需要通过解释器帮助我们正确理解他人的真正意图。

27.2 定义

解释器模式(Interpreter):给定一个语言,定义它的文法的一种表示,并定义一个解释器,这个解释器使用该表示来解释语言中的句子。

解释器结构图

27.3 Show me the code

  1. 基本代码
class Program
{
    static void Main(string[] args)
    {
        Context context = new Context();
        IList<AbstractExpression> list = new List<AbstractExpression>();
        list.Add(new TerminalExpression());
        list.Add(new NonterminalExpression());
        list.Add(new TerminalExpression());
        list.Add(new TerminalExpression());

        foreach (AbstractExpression exp in list)
        {
            exp.Interpret(context);
        }

        Console.Read();
    }
}

class Context
{
    private string input;
    public string Input
    {
        get { return input; }
        set { input = value; }
    }

    private string output;
    public string Output
    {
        get { return output; }
        set { output = value; }
    }
}

// 抽象表达式,声明一个抽象的解释操作,这个接口为抽象语法树中所有节点所共享
abstract class AbstractExpression
{
    public abstract void Interpret(Context context);
}

// 终结符表达式,实现与文法中的终结符相关联的解释操作。
class TerminalExpression : AbstractExpression
{
    public override void Interpret(Context context)
    {
        Console.WriteLine("终端解释器");
    }
}

// 非终结符表达式,为文法中的非终结符实现解释操作。
// 对文法中每一条规则R2、R2.....Rn都需要一个具体的非终结表达式类
class NonterminalExpression : AbstractExpression
{
    public override void Interpret(Context context)
    {
        Console.WriteLine("非终端解释器");
    }
}

结果:

终端解释器
非终端解释器
终端解释器
终端解释器
  1. 乐谱解释控制台代码实现:

class Program
{
    static void Main(string[] args)
    {
        PlayContext context = new PlayContext();
        //音乐-上海滩
        Console.WriteLine("上海滩:");
        //context.演奏文本 = "T 500 O 2 E 0.5 G 0.5 A 3 E 0.5 G 0.5 D 3 E 0.5 G 0.5 A 0.5 O 3 C 1 O 2 A 0.5 G 1 C 0.5 E 0.5 D 3 D 0.5 E 0.5 G 3 D 0.5 E 0.5 O 1 A 3 A 0.5 O 2 C 0.5 D 1.5 E 0.5 D 0.5 O 1 B 0.5 A 0.5 O 2 C 0.5 O 1 G 3 P 0.5 O 2 E 0.5 G 0.5 A 3 E 0.5 G 0.5 D 3 E 0.5 G 0.5 A 0.5 O 3 C 1 O 2 A 0.5 G 1 C 0.5 E 0.5 D 3 D 0.5 E 0.5 G 3 D 0.5 E 0.5 O 1 A 3 A 0.5 O 2 C 0.5 D 1.5 E 0.5 D 0.5 O 1 B 0.5 A 0.5 G 0.5 O 2 C 3 P 0.5 O 3 C 0.5 C 0.5 O 2 A 0.5 O 3 C 2 P 0.5 O 2 A 0.5 O 3 C 0.5 O 2 A 0.5 G 2.5 G 0.5 E 0.5 A 1.5 G 0.5 C 1 D 0.25 C 0.25 D 0.5 E 2.5 E 0.5 E 0.5 D 0.5 E 2.5 O 3 C 0.5 C 0.5 O 2 B 0.5 A 3 E 0.5 E 0.5 D 1.5 E 0.5 O 3 C 0.5 O 2 B 0.5 A 0.5 E 0.5 G 2 P 0.5 O 2 E 0.5 G 0.5 A 3 E 0.5 G 0.5 D 3 E 0.5 G 0.5 A 0.5 O 3 C 1 O 2 A 0.5 G 1 C 0.5 E 0.5 D 3 D 0.5 E 0.5 G 3 D 0.5 E 0.5 O 1 A 3 A 0.5 O 2 C 0.5 D 1.5 E 0.5 D 0.5 O 1 B 0.5 A 0.5 G 0.5 O 2 C 3 ";
        context.PlayText = "T 500 O 2 E 0.5 G 0.5 A 3 E 0.5 G 0.5 D 3 E 0.5 G 0.5 A 0.5 O 3 C 1 O 2 A 0.5 G 1 C 0.5 E 0.5 D 3 ";
        //音乐-隐形的翅膀
        //Console.WriteLine("隐形的翅膀:"); 
        //context.演奏文本 = "T 1000 O 1 G 0.5 O 2 C 0.5 E 1.5 G 0.5 E 1 D 0.5 C 0.5 C 0.5 C 0.5 C 0.5 O 1 A 0.25 G 0.25 G 1 G 0.5 O 2 C 0.5 E 1.5 G 0.5 G 0.5 G 0.5 A 0.5 G 0.5 G 0.5 D 0.25 E 0.25 D 0.5 C 0.25 D 0.25 D 1 A 0.5 G 0.5 E 1.5 G 0.5 G 0.5 G 0.5 A 0.5 G 0.5 E 0.5 D 0.5 C 0.5 C 0.25 D 0.25 O 1 A 1 G 0.5 A 0.5 O 2 C 1.5 D 0.25 E 0.25 D 1 E 0.5 C 0.5 C 3 O 1 G 0.5 O 2 C 0.5 E 1.5 G 0.5 E 1 D 0.5 C 0.5 C 0.5 C 0.5 C 0.5 O 1 A 0.25 G 0.25 G 1 G 0.5 O 2 C 0.5 E 1.5 G 0.5 G 0.5 G 0.5 A 0.5 G 0.5 G 0.5 D 0.25 E 0.25 D 0.5 C 0.25 D 0.25 D 1 A 0.5 G 0.5 E 1.5 G 0.5 G 0.5 G 0.5 A 0.5 G 0.5 E 0.5 D 0.5 C 0.5 C 0.25 D 0.25 O 1 A 1 G 0.5 A 0.5 O 2 C 1.5 D 0.25 E 0.25 D 1 E 0.5 C 0.5 C 3 E 0.5 G 0.5 O 3 C 1.5 O 2 B 0.25 O 3 C 0.25 O 2 B 1 A 0.5 G 0.5 A 0.5 O 3 C 0.5 O 2 E 0.5 D 0.5 C 1 C 0.5 C 0.5 C 0.5 O 3 C 1 O 2 G 0.25 A 0.25 G 0.5 D 0.25 E 0.25 D 0.5 C 0.25 D 0.25 D 3 E 0.5 G 0.5 O 3 C 1.5 O 2 B 0.25 O 3 C 0.25 O 2 B 1 A 0.5 G 0.5 A 0.5 O 3 C 0.5 O 2 E 0.5 D 0.5 C 1 C 0.5 C 0.5 C 0.5 O 3 C 1 O 2 G 0.25 A 0.25 G 0.5 D 0.25 E 0.25 D 0.5 C 0.5 C 3 ";
        Expression expression = null;
        try
        {
            while (context.PlayText.Length > 0)
            {
                string str = context.PlayText.Substring(0, 1);
                switch (str)
                {
                    case "O":
                        expression = new Scale();
                        break;
                    case "T":
                        expression = new Speed();
                        break;
                    case "C":
                    case "D":
                    case "E":
                    case "F":
                    case "G":
                    case "A":
                    case "B":
                    case "P":
                        expression = new Note();
                        break;

                }
                expression.Interpret(context);

            }
        }
        catch (Exception ex)
        {
            Console.WriteLine(ex.Message);
        }

        Console.Read();
    }
}
//演奏内容
class PlayContext
{
    //演奏文本
    private string text;
    public string PlayText
    {
        get { return text; }
        set { text = value; }
    }
}

//表达式
abstract class Expression
{
    //解释器
    public void Interpret(PlayContext context)
    {
        if (context.PlayText.Length == 0)
        {
            return;
        }
        else
        {
            string playKey = context.PlayText.Substring(0, 1);
            context.PlayText = context.PlayText.Substring(2);
            double playValue = Convert.ToDouble(context.PlayText.Substring(0, context.PlayText.IndexOf(" ")));
            context.PlayText = context.PlayText.Substring(context.PlayText.IndexOf(" ") + 1);

            Excute(playKey, playValue);

        }
    }
    //执行
    public abstract void Excute(string key, double value);
}

//音符
class Note : Expression
{
    public override void Excute(string key, double value)
    {
        string note = "";
        switch (key)
        {
            case "C":
                note = "1";
                break;
            case "D":
                note = "2";
                break;
            case "E":
                note = "3";
                break;
            case "F":
                note = "4";
                break;
            case "G":
                note = "5";
                break;
            case "A":
                note = "6";
                break;
            case "B":
                note = "7";
                break;

        }
        Console.Write("{0} ", note);
    }
}

//音阶
class Scale : Expression
{
    public override void Excute(string key, double value)
    {
        string scale = "";
        switch (Convert.ToInt32(value))
        {
            case 1:
                scale = "低音";
                break;
            case 2:
                scale = "中音";
                break;
            case 3:
                scale = "高音";
                break;

        }
        Console.Write("{0} ", scale);
    }
}

//音速
class Speed : Expression
{
    public override void Excute(string key, double value)
    {
        string speed;
        if (value < 500)
            speed = "快速";
        else if (value >= 1000)
            speed = "慢速";
        else
            speed = "中速";

        Console.Write("{0} ", speed);
    }
}

27.4 总结

  1. 当有一个语言需要解释执行,并且你可将该语言中的句子表示为一个抽象语法树时,可使用解释器模式;
  2. 优点:比较容易改变和扩展文法,因为该模式使用类来表示文法规则,可使用继承实现;也比较容易实现文法,因为定义抽象语法树中各个节点的类的实现大体类似,这些类都易于直接编写。
  3. 缺点:每个文法中的每一条规则至少定义了一个类,因为包含许多规则的文法可能难以管理和维护。
  4. 建议:当文法非常复杂时,使用其他的技术如语法分析程序或编译器生成器来处理。

28访问者模式

28.1 Example

大头平时喜欢吃汉堡之类的快餐。

因此每次去快餐店,大头总是先了解一下快餐店最近的促销产品,然后了解一下所有可购买产品的状态,再根据自己的喜好进行购买。这就是访问者模式。访问一个对象,可以对这个对象所有子类进行读取。

Picture Source: Refactoring GURU

28.2 定义

访问者模式(Visitor):表示一个作用于某对象结构中的各元素的操作。它使你可以在不改变各元素的类的前提下定义作用于这些元素的新操作

访问者模式结构图

28.3 Show me the code

class Program
{
    static void Main(string[] args)
    {
        ObjectStructure o = new ObjectStructure();
        o.Attach(new ConcreteElementA());
        o.Attach(new ConcreteElementB());

        ConcreteVisitor1 v1 = new ConcreteVisitor1();
        ConcreteVisitor2 v2 = new ConcreteVisitor2();

        o.Accept(v1);
        o.Accept(v2);

        Console.Read();
    }
}

abstract class Visitor
{
    public abstract void VisitConcreteElementA(ConcreteElementA concreteElementA);

    public abstract void VisitConcreteElementB(ConcreteElementB concreteElementB);
}

class ConcreteVisitor1 : Visitor
{
    public override void VisitConcreteElementA(ConcreteElementA concreteElementA)
    {
        Console.WriteLine("{0}被{1}访问", concreteElementA.GetType().Name, this.GetType().Name);
    }

    public override void VisitConcreteElementB(ConcreteElementB concreteElementB)
    {
        Console.WriteLine("{0}被{1}访问", concreteElementB.GetType().Name, this.GetType().Name);
    }
}

class ConcreteVisitor2 : Visitor
{
    public override void VisitConcreteElementA(ConcreteElementA concreteElementA)
    {
        Console.WriteLine("{0}被{1}访问", concreteElementA.GetType().Name, this.GetType().Name);
    }

    public override void VisitConcreteElementB(ConcreteElementB concreteElementB)
    {
        Console.WriteLine("{0}被{1}访问", concreteElementB.GetType().Name, this.GetType().Name);
    }
}

abstract class Element
{
    public abstract void Accept(Visitor visitor);
}

class ConcreteElementA : Element
{
    public override void Accept(Visitor visitor)
    {
        visitor.VisitConcreteElementA(this);
    }

    public void OperationA()
    { }
}

class ConcreteElementB : Element
{
    public override void Accept(Visitor visitor)
    {
        visitor.VisitConcreteElementB(this);
    }

    public void OperationB()
    { }
}

class ObjectStructure
{
    private IList<Element> elements = new List<Element>();

    public void Attach(Element element)
    {
        elements.Add(element);
    }

    public void Detach(Element element)
    {
        elements.Remove(element);
    }

    public void Accept(Visitor visitor)
    {
        foreach (Element e in elements)
        {
            e.Accept(visitor);
        }
    }
}

28.4 总结

  1. 访问者模式适用于数据结构相对稳定的系统,将数据结构和作用于结构上的操作耦合解脱开,使得操作集合可以相对自由地演化。
  2. 当你需要对一个复杂对象结构,如对象树中所有元素执行某些操作,可使用访问者模式;
  3. 优点:增加新的访问者,即增加新操作比较容易。访问者模式将有关行为集中到一个访问者对象中。
  4. 缺点:增加新的数据结构比较困难,有的操作需要重新修改。

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

aws s3 参与s3game寻找宝藏游戏挑战学习s3对象存储

参考资料 Pirates S3game workshop http://s3game-level1.s3-website.us-east-2.amazonaws.com/level1.html https://blog.benclmnt.com/notes/s3-game/ https://awscli.amazonaws.com/v2/documentation/api/latest/reference/s3/index.html 强烈推荐这种寓教于乐的方式学…

【ROS2 入门】ROS 2 actions 概述

大家好&#xff0c;我是虎哥&#xff0c;从今天开始&#xff0c;我将花一段时间&#xff0c;开始将自己从ROS1切换到ROS2&#xff0c;在上一篇中&#xff0c;我们一起了解ROS 2中Parameters&#xff0c; 这一篇&#xff0c;我们主要会围绕ROS中另外一个重要的概念“Actions ”来…

Linux 系统调用的实现(x86_64)

目录 1、系统调用的定义 1.1 SYSCALL_METADATA宏 1.2 __SYSCALL_DEFINEx定义 2、系统调用表-sys_call_table数组的定义 3、用户态系统调用流程 kernel 5.10 1、系统调用的定义 系统调用的定义我们其实都不陌生&#xff0c;类似这样的函数SYSCALL_DEFINE0&#xff0c; SYSC…

C语言常见错误汇总

1 数组遍历时使用sizeof(a) 任务&#xff1a;有个数组&#xff0c;找出第二大的数&#xff0c;并且打印出来&#xff08;使用*操作数组元素个数&#xff0c;不要使用[]&#xff09; #include<stdio.h> int main01() {int a[] { 100,100,100,234,123,500,32,68,41,99,1…

code.org免费的少儿编程入门平台

现在市面上的少儿编程课&#xff0c;都是先花9.9就能体验几节课&#xff0c;然后要花几千块才能继续学习后面的课程。这些钱大可不必花。 现在给大家推荐一个免费的网站&#xff0c;code.org&#xff0c;它是一个非营利组织创办的网站&#xff0c;目标是让每个学生都能像生物、…

高并发系统设计 --多级缓存

为了提高系统的性能&#xff0c;一般会引入“缓存机制”&#xff0c;将部分热点数据存入缓存中&#xff0c;用空间换取时间&#xff0c;以达到快速响应的目的。 我们对缓存的认知停留在redis&#xff0c;但其实缓存远远不是只有redis的&#xff0c;从客户端发起请求开始&#…

MySQL整体使用》导入数据、约束、多表查询、事务、变量类型、资源占用

我发的MySQL相关内容&#xff1a; C#基础知识体系框架图&#xff0c;及起对应我发过的博客 linux安装mysql8配置使用&#xff0c;并解决常见问题 MySQL常用命令&#xff08;DQL&#xff09; 执行脚本命令&#xff0c;本地生成SQL文件后在服务器执行 // 进入mysql命令控制 m…

svg绘(viewBox viewport preserveAspectRatio)代替png图片等

当我们的代码中需要一个小图标的时候没必要去iconfont进行下载图标使用 要是下载的png格式那么容量还很大 远不如svg 直接自己代码写 记住svg的坐标朝向和数学坐标轴不一样 实现下图添加的小图标 <svg width"20px" height"20px" style"border: …

2023java面试之Zookeeper基础

一、说说 Zookeeper 是什么&#xff1f;直译&#xff1a;从名字上直译就是动物管理员&#xff0c;动物指的是 Hadoop 一类的分布式软件&#xff0c;管理员三个字体现了 ZooKeeper 的特点&#xff1a;维护、协调、管理、监控。简述&#xff1a;有些软件你想做成集群或者分布式&a…

冯诺依曼体系结构

冯诺依曼体系结构 我们常见的计算机&#xff0c;如笔记本。我们不常见的计算机&#xff0c;如服务器&#xff0c;大部分都遵守冯诺依曼体系。 截至目前&#xff0c;我们所认识的计算机&#xff0c;都是有一个个的硬件组件组成&#xff1a; 输入单元&#xff1a;包括键盘, 鼠…

netbeans中配置maven

deploy-发布到远程maven库本节默认maven库为nexusnetbeans中按ctrl1&#xff0c;打开Project窗口&#xff1b;在Project窗口中找到相关的project或module,在项目名上点击鼠标右键&#xff1b;在弹出菜单中找到菜单“Run Maven”的子菜单“Goals”&#xff0c;并点击&#xff0c…

PCB封装创建(IC类+USB)

目录 一&#xff1a;IC类 封装原理图 规格参数选最大。创建过程 1.放置焊盘 2.我们需要八个上图焊盘&#xff0c;可以用特殊粘贴 3.丝印层设置 封装向导 右击0805R&#xff0c;选择footprint 输入焊盘尺寸 二&#xff1a;USB封装 原理图 创建过程 1.放置焊盘&#x…

SSM 03_SpringMVC REST风格 Postman SSM整合 拦截器

01-SpringMVC简介SpringMVC是隶属于Spring框架的一部分&#xff0c;主要是用来进行Web开发&#xff0c;是对Servlet进行了封装。SpringMVC是处于Web层的框架&#xff0c;所以其主要的作用就是用来接收前端发过来的请求和数据然后经过处理并将处理的结果响应给前端&#xff0c;所…

元宇宙时代业务扩张,专精特新小巨人找到了增长“神器”

进入2023年&#xff0c;元宇宙时代正扑面而来。自从脸书公司更名为Meta以来&#xff0c;元宇宙就在全球迅速走红。《福布斯》认为&#xff0c;2030年全球元宇宙的市场规模有望高达5万亿美元。更为重要的是&#xff0c;元宇宙正在成为数实融合的新界面、未来商业的新型基础设施。…

如何在浏览器中安装使用Vue开发者工具?Vue开发者工具的安装使用?可直接提取插件安装使用

一个混迹于Github、Stack Overflow、开源中国、CSDN、博客园、稀土掘金、51CTO等 的野生程序员。 目标&#xff1a;分享更多的知识&#xff0c;充实自己&#xff0c;帮助他人 GitHub公共仓库&#xff1a;https://github.com/zhengyuzh 以github为主&#xff1a; 1、分享前端后端…

【阶段四】Python深度学习08篇:深度学习项目实战:循环神经网络SimpleRNN、LSTM进行淘宝商品评论文本情感分析

本篇的思维导图: 项目背景 随着信息化社会的发展,互联网成为方便、快捷的信息获取渠道之一。在电子商务和社会网站中,大量非结构化的评论文本作为最直观的用户体验数据被保存下来。如何利用这些文字信息归纳出用户对某一事、物的观点态度成为自然语言(NLP)领域一项…

RNN从理论到实战【实战篇】

来源&#xff1a;投稿 作者&#xff1a;175 编辑&#xff1a;学姐 昨天的文章中&#xff0c;我们学习了RNN的理论部分&#xff0c;本文来看如何实现它&#xff0c;包括堆叠RNN和双向RNN。从而理解它们的原理。最后看一个应用到词性标注任务的实战。 RNNCell 首先实现单时间步…

iMX6ULL —按键输入捕获与GPIO输入配置与高低电平读取

硬件介绍1.1 板子上按键原理图先来看原理图&#xff0c;我板子上有4个按键sw1~sw4:1.1.1 SW1SW1是板子的系统复位按键&#xff0c;不可编程使用1.1.2 SW2、SW3SW2&#xff1a;SNVS_TAMPER1&#xff0c;GPIO5_1平时是低电平&#xff0c;按下去是高电平。SW3&#xff1a;ONOFF它也…

2023年java面试题之zookeeper基础2

一、请描述一下 Zookeeper 的通知机制是什么&#xff1f;Zookeeper 允许客户端向服务端的某个 znode 注册一个 Watcher 监听&#xff0c;当服务端的一些指定事件触发了这个 Watcher &#xff0c;服务端会向指定客户端发送一个事件通知来实现分布式的通知功能&#xff0c;然后客…

echarts基本用法

目录 tooltip:{ // 设置提示框信息 图表的提示框组件 legend:{ // 图例组件 toolbox : { //工具箱组件 可以另存为图片等功能 grid{ //网格配置 grid可以控制线型图 柱状图 图表大小 xAxs: { // 设置x轴的相关配置 y轴同理 series:[ // 系列图表 它决定着显示那种…