精华内容
下载资源
问答
  • 本文内容引用自《大话这设计模式》这本书第一章节简单工厂设计模式,供自己提高代码水平使用。 案例也同样采用计算器功能实现方式展开 实现功能---->封装---->继承---->多态---->面向对象 ...

    一、介绍

    		本文内容引用自《大话这设计模式》这本书第一章节简单工厂设计模式,供自己提高代码水平使用。
    		案例也同样采用计算器功能实现方式展开    
    		实现功能---->封装---->继承---->多态---->面向对象			
    

    二、为什么采用面向对象编程而不是面向过程呢?

    在当今互联网开发的大型企业中你会发现,当你接到一个功能模块的时候不会给你完整的项目源码,特别是核心的东西,为什么呢?

    仔细想一下,如果公司把员工薪资分发系统让你修改,这时你动了一下坏心思,做了一层 If 判断,如果名字是自己的话薪资*2,是不是公司就赔了?况且公司也不会这么傻,把这种核心的功能让新手做修改,这就引入代码的面向对象,将代码分为逻辑层和业务层分开处理,这样不仅逻辑清晰方便后期的修改,也方便了公司为自身的保护。

    三、实例讲解

    我们创建一个主控制台,先用一个面向过程的编程方式去写一个计算器功能,代码如下

            while (true)
            {
                try
                {
                    Console.WriteLine("请输入第一个数字一");
                    double number1 = double.Parse(Console.ReadLine());
                    Console.WriteLine("请输入运算符");
                    string symbol = Console.ReadLine();
                    Console.WriteLine("请输入第一个数字二");
                    double number2 = double.Parse(Console.ReadLine());
                    switch (symbol)
                    {
                        case "+":
                            Console.WriteLine(number1 + number2);
                            break;
                        case "-":
                            Console.WriteLine(number1 - number2);
                            break;
                        case "*":
                            Console.WriteLine(number1 * number2);
                            break;
                        case "/":
                            if (number2 == 0d)
                            {
                                Console.WriteLine("被除数不能为0");
                                break;
                            }
                            Console.WriteLine(number1 / number2);
                            break;
                        default:
                            break;
                    }
                }
                catch (Exception ex)
                {
                    Console.WriteLine(ex);
                }
            }
    

    这时候我们分析一下

    1、首先逻辑是没有问题的,如果后期修改怎么办?是否需要将完整的代码拿出来修改?
    2、如果我们后期需要增加一个开平方根,时候会影响了其他运算的逻辑?
    3、如果我们现在需要开发另外一个平台的计算器功能,我们能都将这个代码拿过去直接复用?

    先回答第一个问题,这个代码比较简单,修改起来也比较方便,但是如果项目需求比较大,我们可能会话费很长时间去找当时写的代码,这时候会非常话费时间,那么我们可以将逻辑层和业务层分开,代码如下

    我们将业务层划分出来:

    public class Operation
    {
    
        public static double GetResult(double number1,double number2,string symbol) 
        {
            double result = 0;
            switch (symbol)
            {
                case "+":
                    result = number1 + number2;
                    break;
                case "-":
                    result = number1 - number2;
                    break;
                case "*":
                    result = number1 * number2;
                    break;
                case "/":
                    if (number2 == 0d)
                    {
                        Console.WriteLine("被除数不能为0");
                        break;
                    }
                    result = number1 / number2;
                    break;
                default:
                    break;
            }
            return result;
        }
    }
    

    逻辑层

    while (true)
            {
                try
                {
                    Console.WriteLine("请输入第一个数字一");
                    double number1 = double.Parse(Console.ReadLine());
                    Console.WriteLine("请输入运算符");
                    string symbol = Console.ReadLine();
                    Console.WriteLine("请输入第一个数字二");
                    double number2 = double.Parse(Console.ReadLine());
    
                    double result = Operation.GetResult(number1,number2,symbol);
                    Console.WriteLine("结果为"+result);
                }
                catch (Exception ex)
                {
                    Console.WriteLine(ex);
                }
            }
    

    这时候是否显得比较整洁,之后修改的时候我们直接使用Operation这个脚本修改即可

    回答第二个问题

    如果这时候我们需要增加一个需求,当我们做➕法运算的时候,我们得到的值始终是要多➕2的,这时候我们如果按照当前的方法修改的话,我们需要改动Operation这个类中的GetResult方法即可,但是这个方法里面包含了4个逻辑算式,如果这时候不小心动了其他的怎么办?所以这时候我们就要引入面向对象知识,封装,继承,多态的方式去修改当前代码。代码如下

    public class Operation
    {
    
        private double m_number1;
    
        private double m_number2;
    
        public double Number1 { get { return m_number1; } set { m_number1 = value; } }
    
        public double Number2 { get { return m_number2; } set { m_number2 = value; } }
    
    
        public virtual double GetResult() 
        {
            double result = 0;
            return result;
        }
    }
    
    public class Add : Operation 
    {
        public override double GetResult()
        {
            double result = Number1 + Number2;
            return result;
        }
    }
    
    public class Subtract : Operation
    {
        public override double GetResult()
        {
            double result = Number1 - Number2;
            return result;
        }
    }
    
    public class Multiply : Operation
    {
        public override double GetResult()
        {
            double result = Number1 * Number2;
            return result;
        }
    }
    
    public class Divide : Operation
    {
        public override double GetResult()
        {
            if(Number2 == 0)
                throw new Exception("除数不能为0");
            double result = Number1 / Number2;
            return result;
        }
    }
    

    继承
    修改业务层层,增加两个属性,并且重写一个方法,在定义四个不同的运算符类,分别继承业务层Operation,根据不同的方式重写基类方法

    这里回答第三个问题

    如何复用我们当前写的东西呢?这里可能对于刚开始编程的人来说不会区分对象,这里我们将每一个运算式分别定义一个对象,然后这里的每一个对象分别有两个属性,数字一和数字二,这样理解就比较清晰,既然明白了对象,我们就将面向对象的多态简单工厂设计模式引入到里面,从而达到我们所写代码的复用性,代码如下:

    简单工厂:(多态)

    public static Operation CreateOperation(string symbol) 
        {
            Operation oper = null;
            switch (symbol)
            {
                case "+":
                    oper = new Add();
                    break;
                case "-":
                    oper = new Subtract();
                    break;
                case "*":
                    oper = new Multiply();
                    break;
                case "/":
                    oper = new Divide();
                    break;
                default:
                    break;
            }
            return oper;
        }
    

    业务层:(解耦合)

    public class Operation
    {
    
        private double m_number1;
    
        private double m_number2;
    
        public double Number1 { get { return m_number1; } set { m_number1 = value; } }
    
        public double Number2 { get { return m_number2; } set { m_number2 = value; } }
    
    
        public virtual double GetResult() 
        {
            double result = 0;
            return result;
        }
    }
    
    public class Add : Operation 
    {
        public override double GetResult()
        {
            double result = Number1 + Number2;
            return result;
        }
    }
    
    public class Subtract : Operation
    {
        public override double GetResult()
        {
            double result = Number1 - Number2;
            return result;
        }
    }
    
    public class Multiply : Operation
    {
        public override double GetResult()
        {
            double result = Number1 * Number2;
            return result;
        }
    }
    
    public class Divide : Operation
    {
        public override double GetResult()
        {
            if(Number2 == 0)
                throw new Exception("除数不能为0");
            double result = Number1 / Number2;
            return result;
        }
    }
    

    主控制台:

    class Program
    {
        static void Main(string[] args)
        {
    
            while (true)
            {
                try
                {
                    Console.WriteLine("请输入第一个数字一");
                    double number1 = double.Parse(Console.ReadLine());
                    Console.WriteLine("请输入运算符");
                    string symbol = Console.ReadLine();
                    Console.WriteLine("请输入第一个数字二");
                    double number2 = double.Parse(Console.ReadLine());
    
                    Operation oper;
                    oper = OperationFactory.CreateOperation(symbol);
                    oper.Number1 = number1;
                    oper.Number2 = number2;
                    Console.WriteLine("结果为"+oper.GetResult());
                }
                catch (Exception ex)
                {
                    Console.WriteLine(ex);
                }
            }
        }
    }
    

    总结:

    巧妙的使用面向对象的封装继承和多态会让我们后期的维护节约不少时间,提高了开发的效率,当我们将代码移植到别的平台的时候,我们只需要将业务层Operation 和 OperationFactory移植即可方便调用。

    展开全文
  • 简单工厂模式计算器)(JAVA)

    千次阅读 2015-01-16 18:54:58
    之前使用C++写过一个计算器功能使用设计模式是简单工厂模式,这次使用JAVA来实现。 在此次编写的时候我发现一个问题,就是为什么工厂类要使用静态方法来实例化对象。 原因是因为,如果不使用静态方法来实例化...

    之前使用C++写过一个计算器功能,使用的设计模式是简单工厂模式,这次使用JAVA来实现。

    在此次编写的时候我发现一个问题,就是为什么工厂类要使用静态方法来实例化对象。

    原因是因为,如果不使用静态方法来实例化对象也可以,但是还需要先实例化工厂类再实例化需要的那个对象,这样就实例化了2个对象,实际上在程序中起运算作用的就只是后面那个而已,这样就浪费了空间,所以使用静态方法来实例化对象还是比较优化的。

    下面贴上代码,比较简单就不注释了:

    展开全文
  • 1,使用电池,随意移动,充分体现掌上计算器这主题,并有电池电量显示功能. 2,显示时间功能,基本够用,可以调节时间 3,按键音功能,可设置关/启按键音。不过,我觉得本身按键的声音已经大于按键音了 4,自动调节屏幕亮度,...
  • 图形计算器-源码

    2021-02-15 20:18:45
    您将使用的三种设计模式什么。 对于每种设计模式,您必须: 责任链:我们选择“责任链”是因为我们认为要创建可靠的GUI界面,我们需要一组处理程序来处理信息。 例如,通过按字母i(用于插入),用户将可以在界面...
  • 什么计算器+? Calculator +是一款易于使用,无按钮的科学计算器。 它具有简约的设计,由一个用于输入的文本字段和一个用于输出的显示屏组成,以避免按钮附带的笨拙。 尽管设计简单,但功能强大,足以计算传统...
  • 在现实的开发中,这些简单的自定义语言可以通过现有的编程语言来设计,如果所基于的编程语言是面向对象语言,此时可以使用解释器模式来实现自定义语言 什么是解释器模式 Interpreter Pattern 定义一个语言的方法,...

    前言

    目前计算器编程语言有好几百种,但是有时候人们还是希望能用一些简单的语言表达实现一些特定的操作,比如输入一个文件,它就可以按照预定的格式进行解释,从而实现相应的功能。

    在现实的开发中,这些简单的自定义语言可以通过现有的编程语言来设计,如果所基于的编程语言是面向对象语言,此时可以使用解释器模式来实现自定义语言

    什么是解释器模式 Interpreter Pattern

    定义一个语言的方法,并且建立一个解释器来解释该语言中的句子,这里的"语言"是指使用规定和语言的代码。解释器模式是一种对象行为型模式

    解释器模式的优点

    (1)、易于改变和扩展文法,由于解释器模式中使用类来表示语言的文法规则,因此可以通过继承等机制改变和扩展文法。

    (2)、每一条文法规则都可以表示一个类,因此可以方便地实现一个简单的语言。

    (3)、实现文法比较容易,在抽象语法树中每一个表示式节点类的实现方式都是相似的,这些类的代码编写都不会特别复杂,还可以通过一些工具自动生成节点类代码

    (4)、增加新的解释表达式比较方便,如果用户需要增加新的解释表达式只需要对应增加一个新的终结符表达式或非终结符表达式类,原有表达式类代码无须修改,符合开闭原则

    解释器模式的缺点

    (1)、对于复杂文法难以维护,在解释器模式中,每一个规则至少需要定义一个类,因此如果一个语言包含太多文法规则,类的个数会急剧增加,导致系统难以维护和管理,此时可以考虑使用语法分析程序等方式来取代解释器模式

    (2)、执行效率低。由于在解释器模式总使用了大量的循环和递归调用,因此在解释器较为复杂的句子时速度很慢,而且代码调试过程也比较麻烦

    解释器模式适用的场景

    (1)、可以将一个需要解释执行的语言中的句子表示为一个抽象语法树

    (2)、一些重复出现的问题可以用一种简单的语言来进行表达

    (3)、一个语言的中文法较为简单

    (4)、当执行效率不是关键问题时(毕竟解释器模式的执行效率并不高)

    解释器模式的具体实现

    目录结构(模拟机器人指令)

    抽象基类

    //本实例对机器人控制指令的输出结果进行模拟,将英文指令翻译为中文指令,实际情况是调用
    //不同的控制程序进行机器人的控制,包括对移动方向、方式和距离的控制等
    public abstract class AbstractNode {
        public abstract String interpret();
    }
    

    具体类

    package com.company.node;
    
    //动作解释:终结符表达式
    public class ActionNode extends AbstractNode {
        private String action;
    
        public ActionNode(String action) {
            this.action = action;
        }
    
        @Override
        //动作移动方式表示式的解释操作
        public String interpret() {
            if(action.equalsIgnoreCase("move")){
                return "移动";
            }else  if(action.equalsIgnoreCase("run")){
                return  "快速移动";
            }else {
                return "无效指令";
            }
        }
    }
    
    package com.company.node;
    
    import com.company.node.AbstractNode;
    
    //And解释:非终结符表达式
    public class AndNode extends AbstractNode {
        private AbstractNode left;  //And的左表达式
        private AbstractNode right; //ANd的右表达式
    
        public AndNode(AbstractNode left, AbstractNode right) {
            this.left = left;
            this.right = right;
        }
    
        @Override
        //And表达式解释操作
        public String interpret() {
            return left.interpret()+"再"+right.interpret();
        }
    }
    
    package com.company.node;
    
    import com.company.node.AbstractNode;
    
    //方向解释:终结符表达式
    public class DirectionNode extends AbstractNode {
        private String direction;
    
        public DirectionNode(String direction) {
            this.direction = direction;
        }
    
        @Override
        //方向表达式的解释操作
        public String interpret() {
            if(direction.equalsIgnoreCase("up")){
                return "向上";
            }else  if(direction.equalsIgnoreCase("down")){
                return "向下";
            }else if(direction.equalsIgnoreCase("left")){
                return "向左";
            }else if(direction.equalsIgnoreCase("right")){
                return "向右";
            }else {
                return "无效指令";
            }
        }
    }
    
    package com.company.node;
    
    import com.company.node.AbstractNode;
    
    //距离解释:终结符表达式
    public class DistanceNode extends AbstractNode {
        private String distance;
    
        public DistanceNode(String distance) {
            this.distance = distance;
        }
    
        @Override
        //距离表达式的解释操作
        public String interpret() {
            return this.distance;
        }
    }
    
    package com.company.node;
    
    import com.company.node.AbstractNode;
    
    //简答句子解释:非终结符表达式
    public class SentCeNode extends AbstractNode {
        private AbstractNode direction;
        private AbstractNode action;
        private AbstractNode distance;
    
        public SentCeNode(AbstractNode direction, AbstractNode action, AbstractNode distance) {
            this.direction = direction;
            this.action = action;
            this.distance = distance;
        }
    
        @Override
        //简单句子的解释操作
        public String interpret() {
            return direction.interpret()+action.interpret()+distance.interpret();
        }
    }
    

    指令处理工具类

    package com.company;
    
    import com.company.node.*;
    
    import java.util.Stack;
    
    //指令处理类:工具类
    public class InstructionHandler {
        private AbstractNode node;
        public void handle(String instruction){
            AbstractNode left=null,right=null;
            AbstractNode direction=null,action=null,distance=null;
            Stack stack=new Stack();  //声明一个栈对象用于储存抽象语法树
            String[]words=instruction.split(" ");  //以空格分隔指定字符串
            for(int i=0;i<words.length;i++){
                //本实例采用栈的方式类处理指令,如果遇到"and",则将其后的3个单词作为3个终结符
                //表达式连成一个一个简单的句子SentceNode作为"and"的右表达式,而将从栈顶弹出的表达式
                //作为"and"的左表达式,最后将新的"and"表达式压入栈中。
                if(words[i].equalsIgnoreCase("and")){
                    left=(AbstractNode) stack.pop();  //弹出栈顶表示式作为左表达式
                    String word1=words[++i];
                    direction=new DirectionNode(word1);
                    String word2=words[++i];
                    action=new ActionNode(word2);
                    String word3=words[++i];
                    distance=new DistanceNode(word3);
                    right=new SentCeNode(direction,action,distance);  //右表达式
                    stack.push(new AndNode(left,right));  //将新表达式压入栈中
                }
                //如果是从头开始进行解释,则将前三个单词组成一个简单的句子SentenceNode并将
                //该句子压入栈中
                else {
                    String word1=words[i];
                    direction=new DistanceNode(word1);
                    String word2=words[++i];
                    action=new ActionNode(word2);
                    String word3=words[++i];
                    distance=new DistanceNode(word3);
                    left=new SentCeNode(direction,action,distance);
                    stack.push(left);
                }
            }
            this.node=(AbstractNode) stack.pop(); //将全部表达式从栈中弹出
        }
        public String output(){
            String result=node.interpret();  //解释表达式
            return  result;
        }
    }
    

    客户端测试类

    package com.company;
    
    public class Client {
    
        public static void main(String[] args) {
            String instruction ="up move 5 and down run 10 and left move 5";
            InstructionHandler handler = new InstructionHandler();
            handler.handle(instruction);
            String outString;
            outString = handler.output();
            System.out.println(outString);
        }
    }
    
    展开全文
  • 读大话设计模式有感

    2021-05-25 11:27:19
    设计模式使得程序更加灵活,容易修改,并且易于复用 封装:对业务方法进行封装,实现方法的复用,不论在什么地方都可以直接移植,重复使用。 继承:在以后程序的拓展时,不会影响到主代码,直接通过继承,进行实现...

    体会

    在编程的过程中,要时刻考虑程序的功能复用性,并将其封装起来
    开发人员应该仅对程序中呈现出频繁变化的那些部分作出抽象,但不需要对每个部分都进行刻意抽象

    序言

    通过封装、继承、多态降低程序的耦合度
    用设计模式使得程序更加灵活,容易修改,并且易于复用
    封装:对业务方法进行封装,实现方法的复用,不论在什么地方都可以直接移植,重复使用。
    继承:在以后程序的拓展时,不会影响到主代码,直接通过继承,进行实现(比方计算器加减乘除功能的基础上,添加一个开平方,只需要继承运算类,并重写运算方法就可以了,不会暴露其他功能给开发者,避免风险,也可以实现拓展)
    多态:在实例化对象时使用,可以根据不同的情况进行实例化不同的对象,并赋值给父类

    MVC : Model是应用对象,View是它在屏幕上的表示,Controller是定义用户界面对用户输入的响应方式。如果不使用MVC,则用户界面设计往往将这些对象混在一起,而MVC则将他们分离以提高灵活性和复用性。

    面向对象设计模式体现的就是抽象的思想;类是对对象的抽象;抽象类是对类的抽象;接口是对行为的抽象。

    单一职责原则: 一个类应该仅有一个引起它变化的原因(不应该把所有的功能代码都放在同一个类中)

    开放-封闭原则: 软件实体(类、模块、函数等等)应该可以扩展,但不能修改

    依赖倒转原则
    抽象不应该依赖细节,细节应该依赖抽象(针对接口编程,而不是对实现编程)
    高层模块不应该依赖低层模块。两个都应该依赖于抽象(Animal animal = new Cat() )

    里氏代换原则:子类型必须能够替换掉他们的父类型

    迪米特法则:如果两个类不必彼此通信,那马这两个类就不应当发生直接的相互作用。如果其中一个类需要调用另一个类的某一个方法的话,可以通过第三者转发这个调用(强调类之间的松耦合)

    合成/聚合复用原则: 尽量使用合成/聚合,尽量不要使用类继承。好处是有助于你保持每个类都被封装,并被集中在单个任务上。这样类和类继承层次会保持较小规模,并且不太可能增长为不可控制的庞然大物。

    敏捷开发原则:不要为代码添加基于猜测的,实际不需要的功能。


    简单工厂模式(解决创建对象问题)

    新建一个简单工厂类,通过传入不同条件,实例化不同的对象(继承同一父类),然后多态向上转型,返回对象

    此处可以考虑使用反射机制来解除分支判断带来的耦合


    策略模式(针对算法: 以相同的方式调用所有的算法,减少各种算法与使用算法类的耦合)

    定义:定义了算法家族,分别封装起来,让它们之间可以互相替换,此模式让算法的变化,不会影响到使用算法的客户

    定义一个算法抽象类,多个类继承这个抽象类,实现其抽象方法(具体算法),定义一个Context类,此类通过构造函数保存某个具体的算法对象(通过构造方法传进来具体的算法对象),此类中有一个方法是调用传入参数的方法,在客户端只需要定义一个Context对象,并根据不同条件传入具体的算法对象即可。

    在此基础上可以进行策略和简单工厂的结合:把简单工厂在客户端的判断移植到策略模式的Context类内进行判断,消除在客户端进行大量判断的行为

    简单工厂模式和策略模式最大的不同是,简单工厂模式需要客户端认识两个类 ,策略模式则只让客户端认识一个类,降低耦合度。

    在分析过程中,听到需要在不同的时间应用不同的业务规则,就可以考虑使用策略模式。


    装饰模式(实质上是一个父类当成参数传入子类中,子类对其的方法进行实现的基础上,加上子类自己的方法,子类又当成参数传递给子类的子类)

    定义一个抽象类,再分别定义一个类(被修饰的类)继承此类,实现其抽象方法,以及定义一个抽象类(用来修饰上一个类)继承此类(把被修饰的类当成参数传入修饰实现类),然后以不同的方式实现抽象类的抽象方法,在被修饰类的实现上进行拓展修饰。

    装饰模式是在已有功能动态的添加更多功能的一种方式
    当系统需要添加功能的时候,并且这个功能只是满足在某种特定情况下才会执行的特殊行为,可以考虑使用装饰模式(这样就能把核心区域和装饰区域分开了,但要注意装饰顺序)


    代理模式(为其他对象提供一种代理以控制对这个对象的访问)

    定义一个抽象类,两个类(具有相同的方法)去进行实现,一个为代理类,这个类代替另一个类去执行,由代理类去接收外部条件,并在代理类的方法中引用另一个类的方法(可以在构造方法的时候创建该类),实现对象的隐藏,只暴露代理类。

    应用场景
    远程代理,用来为一个对象在不同的地址空间提供局部代理
    虚拟代理,存放实例化需要很长时间的真实对象(html网页图片加载慢,使用图片框替代)
    安全代理,用来控制真实对象访问的权限
    智能指引,当调用真实对象时,代理处理另外一些事


    工厂方法模式(定义一个用于创建对象的接口,让子类决定实例化哪一个类。工厂方法是一个类的实例化延迟到其子类)

    定义一个工厂接口,加减乘除各建一个具体工厂实现这个接口,在这些具体工厂的方法中,实例化要返回的对象

    工厂方法与简单工厂最大的区别就是简单工厂在拓展的时候,违背了开闭原则,又保持了封装对象创建过程的优点


    原型模式

    类实现ICloneable接口,实现其中的Clone方法,进行此类的实例化对象进行深浅克隆,避免重复创建相同的对象


    模板方法模式(定义一个操作中的算法的骨架,而将一些步骤延迟到子类中,模板方法使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤)

    把只有小部分差异的多个类(如考试卷),相同之处提炼出来定义为一个模板类,这几个类继承这个类,并重写有差异的方法(考试答案),并向上转型,实现多态。


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

    定义类,把几个组合好的子系统类在此类中实例化,客户根本不知道这几个类的存在只知道暴露出来的这个外部类

    使用场合:比如经典的三层架构,在数据访问层、业务逻辑层、表现层的层与层之间建立外观模式,这样就可以为复杂的子系统提供简单的接口,降低耦合度


    建造者模式(将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示)

    比方在画小人的时候,先定义一个画人抽象类,由各种不同类型(高矮胖瘦,手臂长短)的人去继承他,并实现其内的抽象方法,然后再定义一个指挥者类,对传入的不同类型(此处使用多态)的人的类进行描画

    使用场合:主要用于创建一些复杂的对象,这些对象内部构建间的建造顺序通常是稳定的,但对象内部的构建通常面临着复杂的变化。


    观察者模式(定义了一种一对多的依赖关系,让多个观察者对象同时监听某一个主题对象。这个主题对象在状态发生变化时,会通知所以观察者对象,使他们能够自动更新自己)

    新建一个观察者抽象类,写几个子类继承该抽象类(也可以实现同一个更新接口,因为实际开发中,需要更新的类可能风马牛不相及),新建一个主题者,里面写一个方法添加多个观察者到一个集合里,此类内还要写一个方法调用这些观察者的更新方法(在主题者状态改变的情况下,实现不同实现方式)(在此基础上也可以把主题者类声明为抽象类,进行拓展)

    范例: 前台通知同事,前台看到老板回来了,状态改变,同事即为观察者

    使用场合: 当一个对象的改变需要同事改变其他对象的时候,而且他也不知道具体有多少对象有待改变。

    一个抽象模型里面有两个方面,其中一方面依赖另一个方面,这时使用观察者模式可以将这两者封装在独立的对象中使他们各自队里的改变和复用。
    让耦合的双方都依赖于抽象而不是依赖于具体。从而使得各自的变化都不会影响另一边的变化


    抽象工厂模式(提供一个创建一系列相关或相互依赖对象的接口,而无需指定他们具体的类)

    定义一个抽象工厂接口类,里面的抽象方法返回值为另外几个相关的接口类,继承并实现这些抽象方法,然后对这几个接口类进行继承实现,这样就实现了无需指定他们具体类的目的。

    优缺点:抽象工厂可以很方便的在几个类中进行切换,缺点就是,如果想在增加几个相关接口实现类,需要改动的类比较多。并且如果100个类需要这个抽象工厂的实现类 ,就得声明一百次(此处可以使用IOC的依赖注入,只声明一次放进容器就行了,原理是通过反射机制,然后通过字符串确定实例化的对象,也可加载到配置文件中)


    状态模式(当一个对象的内在状态改变时允许改变其行为,这个对象看起来像是改变了其类)

    经常在一个方法中遇到需要根据不同的分支判断,进行不同操作,这时候可以定义一个状态抽象类(里面含抽象方法),这几个操作分别继承这个状态抽象类,并实现抽象方法,在方法里进行一个小分支的判断,else的情况下,再跳转到另一个操作实现类,以此类推,然后定义一个类,根据传入的条件,从第一个分支操作类(只写这一个)的方法开始

    状态模式主要解决的是当控制一个对象状态转换的条件表达式过于复杂时的情况,把状态的判断逻辑转移到表示不同状态的一系列类当中,可以把复杂的判断逻辑转移简化。


    适配器模式(将一个类的接口转换成客户喜欢的另一个接口。Adapter模式使得原本由于接口不兼容而不能一起工作的那些类可以一起工作)

    一个已经存在或者已经封装死的类想要调用另一个类的方法,写一个适配器类,继承该封装类,在里面实例化另一个类,并写一个调用另一个类方法的方法

    系统的数据和行为都正确,但接口不符时,我们应该考虑用适配器,目的是使控制范围之外的一个原有对象与某个接口匹配。适配器模式主要应用于希望复用一些现存的类,但是接口又与复用环境要求不一致的情况

    这样只需要调用同一个接口就行了,但此模式比较适合在双方都不太容易修改的时候,一般在开发后期或者维护期比较常用。


    备忘录模式(在不破坏封装性的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态,这样以后就可以将该对象恢复到原先保存的状态了)

    先定义一个需要保存的类,再定义一个备忘录类,用来保存需保持类的当前各种属性状态,在需保存类中定义几个方法(以备忘录类对象为参数,把需保存类的各个属性赋值给备忘录类),再定义一个管理者类,进行备忘录类的得到与设置(get,set方法)。游戏保存进度。

    适用于功能比较复杂,但需要维护或记录属性历史的类,或许或者需要保存的属性只是众多属性中的一小部分时。缺点是,状态数据很大很多的时候,在资源消耗上,备忘录对象十分耗内存


    组合模式(将对象组合成树形结构以表示‘部分-整体’的层次结构。组合模式使得用户对单个对象和组合对象的使用具有一致性)

    新建一个抽象类,定义一个枝点类继承该抽象类,并在该类内声明一个集合,实现添加、移除方法(往集合里,通过向上转型),再定义一个叶节点类继承抽象类,空实现添加、移除方法(不具备功能)。

    当需求中体现部分与整体层次的结构时,以及希望用户可以忽略组合对象和单个对象的不同,同意使用组合结构中的所有对象时,就可以考虑使用组合模式。


    迭代器模式(提供一种方法顺序访问一个聚合对象中各个元素,而又不暴露该对象的内部表示)

    定义一个抽象迭代器类,实现此类,对传入的集合进行遍历等各种集合操作

    就是java中的Iterator,现在很多高级编程语言已经把这个模式做到语言中了

    分离了集合对象 的遍历行为,抽象出一个迭代器类来负责,这样既可以做到不暴露集合的内部结构,又可让外部代码透明地访问集合内部的数据


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

    定义一个类,把此类的构造方法设置为私有,不允许外界创建,写一个静态方法,判断要实例化的类是否为null,不为null就创建

    通常我们可以让一个全局变量使得一个对象被访问,但他不能防止你是实例化多个对象。一个最好的办法就是,让类自身负责保存他的唯一实例。这个类可以保证没有其他实例可以被创建,并且提供一个访问该实例的方法

    重点:在多线程程序中,多个线程同时访问,会有可能创建多个实例的,这时需要给这个方法加一把锁。这把锁可以加在判断为null之后,实例化之前,这样可以提高性能,但必须再做一次判断为null,因为可能两个线程同时实例化,这个叫双重锁定


    桥接模式(将抽象部分与它的实现部分分离,使他们都可以独立地变化)

    定义两个抽象类(手机品牌,软件),各自进行多个继承与实现,把软件对象当成参数传入手机品牌,这样再添加手机品牌或软件时,就不需要改动多个类,只需要添加一个类就行了。

    实现系统可能有多角度分类,每一种分类都有可能变化,那么就把这种多角度分离出来让他们独立变化,减少他们之间的耦合。

    两个抽象类之间通过聚合关系(a包含b,但b并不是a的一部分)实现桥接(手机品牌和软件)


    命令模式(将一个请求封装为一个对象,从而使你可用不同的请求对客户进行参数化;对请求排队或记录请求日志,以及支持可撤销的操作)

    拿点烧烤举例,定义一个抽象命令类,把点不同烤串命令继承此类进行实现(传入厨师类,调用厨师类的一个操作方法),再定义一个服务员类(传入命令实现类),此类中含有一个集合,对传入的命令进行添加、移除,以及全部执行。

    优点:较容易设计一个命令队列;在需要的情况下,可以较容易地将命令记入日志;允许接收请求的一方是否要否决请求;可以容易地实现对请求的撤销和重做;加进新的具体命令类不影响其他类;把请求一个操作的对象与知道怎么执行一个操作的对象分割开

    如果不清楚一个系统是否需要命令模式,一般不要着急去实现它,事实上,在需要的时候通过重构实现这个模式并不难,只有在真正需要如撤销/回复操作等功能时,把原来的代码重构为命令模式才有意义。


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

    拿请假、加薪来举例,逐级向上,判断是否有权力进行处理,无权则通过对象的引用传递给上级接着处理。先定义一个管理者抽象类(定义一个方法,参数为自身,进行赋值,由多态进行实现),经理、总监、总经理继承这个类,对其中的抽象方法进行实现(请求条件作为参数),对这些请求进行独立的判断,成功则进行实现,失败则传递给上一级(经理->总监->总经理)

    当客户提交一个请求时,请求是沿链传递直至有一个ConreteHandler对象负责处理它。


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

    定义一个中介者抽象类,实现它,再定义一个同事抽象类,并多种实现,通过具体中介者类,把多种同事类保存到中介者类中,并定义方法进行判断调用哪个保存进去的同事类中的方法

    当系统出现多对多交互复杂的对象群时,不要急于使用中介者模式(因为此模式加大了中介者类的责任),要先反思系统在设计上是不是合理。此模式减少了各个Colleague的耦合,使得可以独立地改变和复用各个Coleague和Mediator。适合集中控制,但使用要考虑清楚。


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

    定义一个分享的抽象类,并分为要分享和不分享进行分别实现,再定义一个分享工厂类,此类内声明一个map集合,构造函数中,把要分享的类生成(也可以不在构造函数中事先生成,也可以在方法中进行判断,需要时再去生成),并存进集合里(判断集合中是否存在,不存在则实例化),再写一个方法,通过key返回map中的对象,实现共享。

    如果一个应用程序使用了大量对象,而大量的这些对象造成了很大的存储开销时就应该考虑使用;还有就是对象的大多数状态可以外部状态,如果删除对象的外部状态,那马可以用相对较小的共享对象取代很多组对象,此时可以考虑使用享元模式。


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

    定义一个文本类,存放要解释的语句,定义一个解释器抽象类,其中定义一个方法(以文本类对象为参数),对文本进行拆分,再定义一个抽象解释方法,然后进行多个实现。

    如果一种特定类型的问题发生的频率足够高,那么可能就值得将该问题的各个实例表示为一个简单语言中的句子。这样就可以构建一个解释器,该解释器通过解释这些句子来解决该问题。(正则表达式)

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


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

    定义一个人抽象类(一个接受抽象方法,以状态实例作为参数),一个状态抽象类(一个男人反应抽象方法,以this男人作为参数,一个女人反应抽象方法,以this女人作为参数),再定义一个对象结构类(一个集合,提供方法对集合进行添加男女和调用显示调用他们的方法),通过先把男女添加进入对象结构类,再遍历调用人的接受方法(传入状态,本质调用状态里的方法)。使用双分派技术,算是最复杂的一种模式

    系统有比较稳定的数据结构,又有易于变化的算法的话,使用访问者模式比较合适,因为访问者模式使得算法操作的增加变得更容易。如果系统的数据结构易于变化,进场要有新的数据对象增加进来,就不适合访问者模式了(比如,人不止有男女,而是不断添加,那就不符合开闭原则了),优点是增加新的操作很容易,因为增加新的操作就意味着增加一个新的访问者,访问者模式将有关的行为集中到一个访问者对象中。缺点就是增加新的数据结构变得困难。

    展开全文
  • 如果用户注册登录对于用户需求、产品功能、商业模式本身带不来任何价值的话,就没必要设计这样的功能。比如一些实用工具类的产品:计算器、手电筒、无社交属性的天气预报等等。 其它像强社交需求的产品(微信)、...
  • 考虑一个计算器功能,只能实现加法和减法...1、明确可使用什么设计模式来实现这个计算器 2、画出适合上述设计模式的类图 3、给出相关代码。其中add方法是加法运算,sub是减法运算 4、以分组为单位认真完成实验报告。
  • APP的注册和登录功能设计

    千次阅读 2016-11-30 09:46:25
     如果用户注册登录对于用户需求、产品功能、商业模式本身带不来任何价值的话,就没必要设计这样的功能。比如一些实用工具类的产品:计算器、手电筒、无社交属性的天气预报等等。  其它像强社交需求的产品(微信)、...
  • Decorator(装饰器模式)

    2017-01-31 00:27:00
    要理解装饰器模式,我们来帮助pizza公司设计一个额外加顶计算器。用户可以要求给pizza加额外的顶料(就是你吃拉面的浇头),然后我们的工作就是将顶料加上,然后计算相应的价格。 什么是装饰器模式 装饰器模式主要...
  • 2.1 为什么是c++ 19 2.2 程序设计范型 19 2.3 过程式程序设计 20 2.3.1 变量和算术 21 2.3.2 检测和循环 22 2.3.3 指针和数组 23 2.4 模块程序设计 23 2.4.1 分别编译 24 2.4.2 异常处理 25 2.5 数据抽象 ...
  • C++程序设计语言(特别版)--源代码

    热门讨论 2012-04-23 07:33:51
    2.1 为什么是c++ 19 2.2 程序设计范型 19 2.3 过程式程序设计 20 2.3.1 变量和算术 21 2.3.2 检测和循环 22 2.3.3 指针和数组 23 2.4 模块程序设计 23 2.4.1 分别编译 24 2.4.2 异常处理 25 2.5 数据抽象 ...
  • 提供的是本书的课后习题源代码,也就是《C++程序设计语言(特别版)题解》的源代码。非书中源代码。 本版本是高清版,是第1版第18次印刷,是书签最全最好的版本。 基本信息 原书名: The C++ Programming Language...
  • 1.1.1 什么是.NET Framework 1 1.1.2 公共语言运行库CLR 2 1.1.3 .NET Framework类库 2 1.1.4 .NET Framework 3.5的新功能 3 1.2 C++应用程序 3 1.3 Visual C++ 2008与Visual Studio 2008 4 1.4 控制台应用程序 7 ...
  • 精通ASP.NET3.5典型模块开发源代码

    热门讨论 2009-07-13 15:34:52
    28.1.2 工厂设计模式在Pet Shop 4.0中的应用 374 28.2 数据层的数据库访问 375 28.2.1 数据访问接口IDAL 375 28.2.2 数据访问的实现类 377 28.2.3 数据访问工厂类DALFactory的实现 379 28.3 数据层中的...
  • 28.1.2 工厂设计模式在Pet Shop 4.0中的应用 374 28.2 数据层的数据库访问 375 28.2.1 数据访问接口IDAL 375 28.2.2 数据访问的实现类 377 28.2.3 数据访问工厂类DALFactory的实现 379 28.3 数据层中的...
  • 考虑到用户对简历信息资源保密性的要求,伯乐助手采用的是基于PC客户端的设计模式,确保用户在安装伯乐助手客户端的电脑上进行本地简历信息管理,这样就杜绝了简历信息的外流。 当用户在更换电脑、重新安装操作系统...
  • Java典型模块

    2012-02-25 18:27:40
    第29章 人员信息管理项目 (接口设计模式+MySQL数据库) 29.1 人员信息管理原理 29.1.1 项目结构框架分析 29.1.2 项目功能业务分析 29.2 人员信息管理项目前期准备 29.2.1 设计数据库 29.2.2 数据库操作相关类 29.3 ...
  • lexyaccmingw

    2007-10-25 22:08:50
    * 什么是观察者模式 * 观察者模式普通实现 * 观察者模式中的必备元素 * 将观察者模式普通实现自动化 * 将观察者模式标准化 * 一个使用自动化观察者模式的复杂例子 * 撤销和重做(Undo/Redo)...
  •  3.7.4 动态代理类的设计模式 81  3.8 小结 83  第2篇 线程开发  第4章 学生并发接水(线程thread) 86  教学视频:9分钟  4.1 学生并发接水原理 86  4.1.1 项目结构框架分析 86  4.1.2 项目功能业务...
  •  3.7.4 动态代理类的设计模式 81  3.8 小结 83  第2篇 线程开发  第4章 学生并发接水(线程thread) 86  教学视频:9分钟  4.1 学生并发接水原理 86  4.1.1 项目结构框架分析 86  4.1.2 项目...
  •  3.7.4 动态代理类的设计模式 81  3.8 小结 83  第2篇 线程开发  第4章 学生并发接水(线程thread) 86  教学视频:9分钟  4.1 学生并发接水原理 86  4.1.1 项目结构框架分析 86  4.1.2 项目...
  •  3.7.4 动态代理类的设计模式 81  3.8 小结 83  第2篇 线程开发  第4章 学生并发接水(线程thread) 86  教学视频:9分钟  4.1 学生并发接水原理 86  4.1.1 项目结构框架分析 86  4.1.2 项目...
  • Unix/Linux 编程实践教程.PDF

    千次下载 热门讨论 2010-09-03 18:34:12
    1.5.3 bc:Unix 的计算器 1.5.4 从 bc/dc 到 Web 1.6 动手实践 1.7 工作步骤和概要图 1.7.1 接下来的工作步骤 1.7.2 Unix 的概要图 1.7.3 Unix 的发展历程 小结 第二章 用户、文件操作与联机帮助:编写 who ...
  • 09 计算器作业以及思路 10 模块导入补充 第24章 01 面向对象设计 02 类相关知识 03 对象相关知识 04 类属性增删改查 05 实例属性的增删改查 06 对象与实例属性 07 对象与实例属性补充 08 面向对象作业 第25章 01...
  • Visual Studio程序员箴言--详细书签版

    热门讨论 2012-10-16 20:37:39
    本书介绍了各种visual studio使用技巧,全书共7章,依次介绍了编辑器、查找功能、环境布局、设计 工具以及解决方案、其他项目与调试方面的技巧。  本书的作者是一位经验丰富的visual studio测试工程师,她将自己...

空空如也

空空如也

1 2 3 4
收藏数 70
精华内容 28
关键字:

计算器功能使用什么设计模式