『设计模式』创建型 —— 原型模式

这部分示例参见小傅哥的 重学Java设计模式——原型模式

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

在这里插入图片描述

案例

每个人都经历过考试,从纸制版到上机答题,大大小小也有几百场。而以前坐在教室里答题身边的人都是一套试卷,考试的时候还能偷摸或者别人给发信息抄一抄答案。

但从一部分可以上机考试的内容开始,在保证大家的公平性一样的题目下,开始出现试题混排更有做的好的答案选项也混排。这样大大的增加了抄的成本,也更好的做到了考试的公平性。

但如果这个公平性的考试需求交给你来完成,你会怎么做?

因为需要实现一个上机考试抽题的服务,因此在这里建造一个题库题目的场景类信息,用于创建;选择题问答题

【选择题】

public class ChoiceQuestion {
    private String name;
    private Map<String, String> option;
    private String key;

    public ChoiceQuestion(String name, Map<String, String> option, String key) {
        this.name = name;
        this.option = option;
        this.key = key;
    }

    public ChoiceQuestion() {
    }

    // getter and setter
}

【问答题】

public class AnswerQuestion {
    private String name;  // 问题
    private String key;   // 答案

    public AnswerQuestion(String name, String key) {
        this.name = name;
        this.key = key;
    }

    public AnswerQuestion() {
    }

    // getter and setter
}

实现

原型模式主要解决的问题就是创建大量重复的类,而我们模拟的场景就需要给不同的用户都创建相同的试卷,但这些试卷的题目不便于每次都从库中获取,甚至有时候需要从远程的 RPC 中获取。这样都是非常耗时的,而且随着创建对象的增多将严重影响效率。

在原型模式中所需要的非常重要的手段就是克隆,在需要用到克隆的类中都需要实现 implements Cloneable 接口。

【题目选项乱序操作工具包】

public class TopicRandomUtil {
    /**
     * 乱序Map元素,记录对应答案key
     *
     * @param option 题目
     * @param key    答案
     * @return Topic 乱序后 {A=c., B=d., C=a., D=b.}
     */
    public static Topic random(Map<String, String> option, String key) {
        Set<String> keySet = option.keySet();
        List<String> keyList = new ArrayList<>(keySet);
        Collections.shuffle(keyList);
        Map<String, String> optionNew = new HashMap<>();
        int idx = 0;
        String keyNew = "";
        for (String next : keySet) {
            String randomKey = keyList.get(idx++);
            if (key.equals(next)) {
                keyNew = randomKey;
            }
            optionNew.put(randomKey, option.get(next));
        }
        return new Topic(optionNew, keyNew);
    }
}

【乱序后的选项】

public class Topic {
    private Map<String, String> option;  // 选项;A、B、C、D
    private String key;           // 答案;B

    public Topic() {
    }

    public Topic(Map<String, String> option, String key) {
        this.option = option;
        this.key = key;
    }

    public Map<String, String> getOption() {
        return option;
    }

    public void setOption(Map<String, String> option) {
        this.option = option;
    }

    public String getKey() {
        return key;
    }

    public void setKey(String key) {
        this.key = key;
    }
}

【克隆对象处理类】

public class QuestionBank implements Cloneable{
    private String candidate; // 考生
    private String number;    // 考号

    private ArrayList<ChoiceQuestion> choiceQuestionList = new ArrayList<ChoiceQuestion>();
    private ArrayList<AnswerQuestion> answerQuestionList = new ArrayList<AnswerQuestion>();

    public QuestionBank append(ChoiceQuestion choiceQuestion) {
        choiceQuestionList.add(choiceQuestion);
        return this;
    }

    public QuestionBank append(AnswerQuestion answerQuestion) {
        answerQuestionList.add(answerQuestion);
        return this;
    }

    @Override
    public Object clone() throws CloneNotSupportedException {
        QuestionBank questionBank = (QuestionBank) super.clone();
        questionBank.choiceQuestionList = (ArrayList<ChoiceQuestion>) choiceQuestionList.clone();
        questionBank.answerQuestionList = (ArrayList<AnswerQuestion>) answerQuestionList.clone();

        // 题目乱序
        Collections.shuffle(questionBank.choiceQuestionList);
        Collections.shuffle(questionBank.answerQuestionList);
        // 答案乱序
        ArrayList<ChoiceQuestion> choiceQuestionList = questionBank.choiceQuestionList;
        for (ChoiceQuestion question : choiceQuestionList) {
            Topic random = TopicRandomUtil.random(question.getOption(), question.getKey());
            question.setOption(random.getOption());
            question.setKey(random.getKey());
        }
        return questionBank;
    }

    public void setCandidate(String candidate) {
        this.candidate = candidate;
    }

    public void setNumber(String number) {
        this.number = number;
    }

    @Override
    public String toString() {

        StringBuilder detail = new StringBuilder("考生:" + candidate + "\r\n" +
                "考号:" + number + "\r\n" +
                "--------------------------------------------\r\n" +
                "一、选择题" + "\r\n\n");

        for (int idx = 0; idx < choiceQuestionList.size(); idx++) {
            detail.append("第").append(idx + 1).append("题:").append(choiceQuestionList.get(idx).getName()).append("\r\n");
            Map<String, String> option = choiceQuestionList.get(idx).getOption();
            for (String key : option.keySet()) {
                detail.append(key).append(":").append(option.get(key)).append("\r\n");;
            }
            detail.append("答案:").append(choiceQuestionList.get(idx).getKey()).append("\r\n\n");
        }

        detail.append("二、问答题" + "\r\n\n");

        for (int idx = 0; idx < answerQuestionList.size(); idx++) {
            detail.append("第").append(idx + 1).append("题:").append(answerQuestionList.get(idx).getName()).append("\r\n");
            detail.append("答案:").append(answerQuestionList.get(idx).getKey()).append("\r\n\n");
        }

        return detail.toString();
    }
}

这里的主要操作内容有三个,分别是:

  • 两个 append(),对各项题目的添加
  • clone(),这里的核心操作就是对对象的复制,这里的复制不只是包括了本身,同时对两个集合也做了复制。只有这样的拷贝才能确保在操作克隆对象的时候不影响原对象
  • 乱序操作,在 list 集合中有一个方法,Collections.shuffle,可以将原有集合的顺序打乱,输出一个新的顺序。在这里我们使用此方法对题目进行乱序操作

PS:深拷贝与浅拷贝问题中,会发生深拷贝的有 java 中的 8 种基本类型以及他们的封装类型,另外还有 String 类型,其余的都是浅拷贝。

【初始化试卷数据】

public class QuestionBankController {
    private QuestionBank questionBank = new QuestionBank();

    public QuestionBankController() {

        Map<String, String> map01 = new HashMap<>();
        map01.put("A", "JAVA2 EE");
        map01.put("B", "JAVA2 Card");
        map01.put("C", "JAVA2 ME");
        map01.put("D", "JAVA2 HE");
        map01.put("E", "JAVA2 SE");

        Map<String, String> map02 = new HashMap<>();
        map02.put("A", "JAVA程序的main方法必须写在类里面");
        map02.put("B", "JAVA程序中可以有多个main方法");
        map02.put("C", "JAVA程序中类名必须与文件名一样");
        map02.put("D", "JAVA程序的main方法中如果只有一条语句,可以不用{}(大括号)括起来");

        Map<String, String> map03 = new HashMap<>();
        map03.put("A", "变量由字母、下划线、数字、$符号随意组成;");
        map03.put("B", "变量不能以数字作为开头;");
        map03.put("C", "A和a在java中是同一个变量;");
        map03.put("D", "不同类型的变量,可以起相同的名字;");

        Map<String, String> map04 = new HashMap<>();
        map04.put("A", "STRING");
        map04.put("B", "x3x;");
        map04.put("C", "void");
        map04.put("D", "de$f");

        Map<String, String> map05 = new HashMap<>();
        map05.put("A", "31");
        map05.put("B", "0");
        map05.put("C", "1");
        map05.put("D", "2");

        questionBank.append(new ChoiceQuestion("JAVA所定义的版本中不包括", map01, "D"))
                .append(new ChoiceQuestion("下列说法正确的是", map02, "A"))
                .append(new ChoiceQuestion("变量命名规范说法正确的是", map03, "B"))
                .append(new ChoiceQuestion("以下()不是合法的标识符",map04, "C"))
                .append(new ChoiceQuestion("表达式(11+3*8)/4%3的值是", map05, "D"))
                .append(new AnswerQuestion("小红马和小黑马生的小马几条腿", "4条腿"))
                .append(new AnswerQuestion("铁棒打头疼还是木棒打头疼", "头最疼"))
                .append(new AnswerQuestion("什么床不能睡觉", "牙床"))
                .append(new AnswerQuestion("为什么好马不吃回头草", "后面的草没了"));
    }

    public String createPaper(String candidate, String number) throws CloneNotSupportedException {
        QuestionBank questionBankClone = (QuestionBank) questionBank.clone();
        questionBankClone.setCandidate(candidate);
        questionBankClone.setNumber(number);
        return questionBankClone.toString();
    }
}

测试验证

public class Test {
    public static void main(String[] args) throws CloneNotSupportedException {
        QuestionBankController questionBankController = new QuestionBankController();
        System.out.println(questionBankController.createPaper("花花", "1000001921032"));
        System.out.println(questionBankController.createPaper("豆豆", "1000001921051"));
        System.out.println(questionBankController.createPaper("大宝", "1000001921987"));
    }
}
考生:花花
考号:1000001921032
--------------------------------------------
一、选择题

第1题:以下()不是合法的标识符
A:STRING
B:de$f
C:void
D:x3x;
答案:C

第2题:表达式(11+3*8)/4%3的值是
A:31
B:0
C:2
D:1
答案:C

第3题:JAVA所定义的版本中不包括
A:JAVA2 EE
B:JAVA2 HE
C:JAVA2 SE
D:JAVA2 ME
E:JAVA2 Card
答案:B

第4题:变量命名规范说法正确的是
A:变量不能以数字作为开头;
B:变量由字母、下划线、数字、$符号随意组成;
C:A和a在java中是同一个变量;
D:不同类型的变量,可以起相同的名字;
答案:A

第5题:下列说法正确的是
A:JAVA程序的main方法中如果只有一条语句,可以不用{}(大括号)括起来
B:JAVA程序中类名必须与文件名一样
C:JAVA程序中可以有多个main方法
D:JAVA程序的main方法必须写在类里面
答案:D

二、问答题

第1题:什么床不能睡觉
答案:牙床

第2题:铁棒打头疼还是木棒打头疼
答案:头最疼

第3题:小红马和小黑马生的小马几条腿
答案:4条腿

第4题:为什么好马不吃回头草
答案:后面的草没了

总结

  • 以上的实际场景模拟了原型模式在开发中重构的作用,但是原型模式的使用频率确实不是很高。如果有一些特殊场景需要使用到,也可以按照此设计模式进行优化。
  • 另外原型设计模式的优点包括:便于通过克隆方式创建复杂对象、也可以避免重复做初始化操作、不需要与类中所属的其他类耦合等。但也有一些缺点如果对象中包括了循环引用的克隆,以及类中深度使用对象的克隆,都会使此模式变得异常麻烦。
  • 终究设计模式是一整套的思想,在不同的场景合理的运用可以提升整体的架构的质量。永远不要想着去硬凑设计模式,否则将会引起过渡设计,以及在承接业务反复变化的需求时造成浪费的开发和维护成本。
  • 初期是代码的优化,中期是设计模式的使用,后期是把控全局服务的搭建。不断的加强自己对全局能力的把控,也加深自己对细节的处理。可上可下才是一个程序员最佳处理方式,选取最合适的才是最好的选择。
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
创建: 1. 单件模式(Singleton Pattern) 2. 抽象工厂(Abstract Factory) 3. 建造者模式(Builder) 4. 工厂方法模式(Factory Method) 5. 原型模式(Prototype) 结构: 6. 适配器模式(Adapter Pattern) 7. 桥接模式(Bridge Pattern) 8. 装饰模式(Decorator Pattern) 9. 组合模式(Composite Pattern) 10. 外观模式(Facade Pattern) 11. 享元模式(Flyweight Pattern) 12. 代理模式(Proxy Pattern) 13. 模板方法(Template Method) 14. 命令模式(Command Pattern) 15. 迭代器模式(Iterator Pattern) 行为: 16. 观察者模式(Observer Pattern) 17. 解释器模式(Interpreter Pattern) 18. 中介者模式(Mediator Pattern) 19. 职责链模式(Chain of Responsibility Pattern) 20. 备忘录模式(Memento Pattern) 21. 策略模式(Strategy Pattern) 22. 访问者模式(Visitor Pattern) 23. 状态模式(State Pattern) 工程结构 ├─01.Singleton │ ├─html │ └─MySingleton │ ├─bin │ │ └─Debug │ ├─obj │ │ └─Debug │ │ └─TempPE │ └─Properties ├─02.ChainOfResponsibility │ ├─html │ ├─My2ChainOfResponsibility │ │ ├─bin │ │ │ └─Debug │ │ ├─obj │ │ │ └─Debug │ │ │ └─TempPE │ │ └─Properties │ └─MyChainOfResponsibility │ ├─bin │ │ └─Debug │ ├─obj │ │ └─Debug │ │ ├─Refactor │ │ └─TempPE │ └─Properties ├─03.FactoryMethodMode │ ├─FactoryMethodMode │ │ ├─bin │ │ │ └─Debug │ │ ├─obj │ │ │ └─Debug │ │ │ └─TempPE │ │ └─Properties │ └─html ├─04.AbstractFactory │ ├─04.1.SimpleFactory │ │ ├─html │ │ └─SimpleFactory │ │ ├─bin │ │ │ └─Debug │ │ ├─obj │ │ │ └─Debug │ │ │ └─TempPE │ │ └─Properties │ ├─AbstractFactory │ │ ├─bin │ │ │ └─Debug │ │ ├─obj │ │ │ └─Debug │ │ │ └─TempPE │ │ └─Properties │ └─html ├─05.BuilderPattern │ ├─html │ └─MyBuilderPattern │ ├─bin │ │ └─Debug │ ├─obj │ │ └─Debug │ │ └─TempPE │ └─Properties ├─06.PrototypePattern │ ├─html │ │ └─C#设计模式(6)——原型模式(Prototype Patt O技术博客_files │ └─PrototypePattern │ ├─bin │ │ └─Debug │ ├─obj │ │ └─Debug │ │ └─TempPE │ └─Properties ├─07.AdapterPattern │ ├─html │ └─MyAdapterPattern │ ├─bin │ │ └─Debug │ ├─obj │ │ └─Debug │ │ └─TempPE │ └─Properties ├─08.BridgePattern │ ├─html │ └─MyBridgePattern │ ├─bin │ │ └─Debug │ ├─obj │ │ └─Debug │ │ └─TempPE │ └─Properties ├─09.DecoratorPattern │ ├─html │ └─MyDecoratorPattern │ ├─bin │ │ └─Debug │ ├─obj │ │ └─Debug │ │ └─TempPE │ └─Properties ├─10.CompositePattern │ ├─html │ └─MyCompositePattern │ ├─bin │ │ └─Debug │ ├─obj │ │ └─Debug │ │ └─TempPE │ └─Properties ├─11.FacadePattern │ ├─html │ └─MyFacadePattern │ ├─bin │ │ └─Debug │ ├─obj │ │ └─Debug │ │ └─TempPE │ └─Properties ├─12.FlyweightPattern │ ├─html │ └─MyFlyweightPattern │ ├─bin │ │ └─Debug │ ├─obj │ │ └─Debug │ │ └─TempPE │ └─Properties ├─13.ProxyPattern │ ├─html │ └─MyProxyPattern │ ├─bin │ │ └─Debug │ ├─obj │ │ └─Debug │ │ └─TempPE │ └─Properties ├─14.TemplateMethod │ ├─html │ └─MyTemplateMethod │ ├─bin │ │ └─Debug │ ├─obj │ │ └─Debug │ │ └─TempPE │ └─Properties ├─15.VisitorPattern │ ├─html │ └─MyVisitorPattern │ ├─bin │ │ └─Debug │ ├─obj │ │ └─Debug │ │ └─TempPE │ └─Properties ├─16.StrategyPattern │ ├─html │ └─MyStrategyPattern │ ├─bin │ │ └─Debug │ ├─obj │ │ └─Debug │ │ └─TempPE │ └─Properties ├─17.StatePattern │ ├─html │ └─StatePattern │ ├─bin │ │ └─Debug │ ├─obj │ │ └─Debug │ │ └─TempPE │ └─Properties ├─18.MementoPattern │ ├─html │ └─MementoPattern │ ├─bin │ │ └─Debug │ ├─obj │ │ └─Debug │ │ └─TempPE │ └─Properties ├─19.MediatorPattern │ ├─html │ └─MediatorPattern │ ├─bin │ │ └─Debug │ ├─obj │ │ └─Debug │ │ └─TempPE │ └─Properties ├─20.OberverPattern │ ├─CatOberverPattern │ │ ├─bin │ │ │ └─Debug │ │ ├─obj │ │ │ └─Debug │ │ │ └─TempPE │ │ └─Properties │ ├─html │ └─MyOberverPattern │ ├─bin │ │ └─Debug │ ├─obj │ │ └─Debug │ │ └─TempPE │ └─Properties ├─21.IteratorPattern │ ├─html │ └─IteratorPattern │ ├─bin │ │ └─Debug │ ├─obj │ │ └─Debug │ │ └─TempPE │ └─Properties ├─22.InterpreterPattern │ ├─html │ └─MyInterpreterPattern │ ├─bin │ │ └─Debug │ ├─obj │ │ └─Debug │ │ └─TempPE │ └─Properties └─23.CommandPattern ├─html └─MyCommandPattern ├─bin │ └─Debug ├─obj │ └─Debug │ └─TempPE └─Properties
针对23种设计模式,分别写了demo并画了类图帮助理解。 总体来说设计模式分为三大类: 创建模式,共五种:工厂方法模式、抽象工厂模式、单例模式、建造者模式原型模式。 结构模式,共七种:适配器模式、装饰器模式、代理模式、外观模式、桥接模式、组合模式、享元模式。 行为模式,共十一种:策略模式、模板方法模式、观察者模式、迭代子模式、责任链模式、命令模式、备忘录模式、状态模式、访问者模式、中介者模式、解释器模式。 其实还有两类:并发模式和线程池模式。 二、设计模式的六大原则 1、开闭原则(Open Close Principle) 开闭原则就是说对扩展开放,对修改关闭。在程序需要进行拓展的时候,不能去修改原有的代码,实现一个热插拔的效果。所以一句话概括就是:为了使程序的扩展性好,易于维护和升级。想要达到这样的效果,我们需要使用接口和抽象类,后面的具体设计中我们会提到这点。 2、里氏代换原则(Liskov Substitution Principle) 里氏代换原则(Liskov Substitution Principle LSP)面向对象设计的基本原则之一。 里氏代换原则中说,任何基类可以出现的地方,子类一定可以出现。 LSP是继承复用的基石,只有当衍生类可以替换掉基类,软件单位的功能不受到影响时,基类才能真正被复用,而衍生类也能够在基类的基础上增加新的行为。里氏代换原则是对“开-闭”原则的补充。实现“开-闭”原则的关键步骤就是抽象化。而基类与子类的继承关系就是抽象化的具体实现,所以里氏代换原则是对实现抽象化的具体步骤的规范。—— From Baidu 百科 3、依赖倒转原则(Dependence Inversion Principle) 这个是开闭原则的基础,具体内容:真对接口编程,依赖于抽象而不依赖于具体。 4、接口隔离原则(Interface Segregation Principle) 这个原则的意思是:使用多个隔离的接口,比使用单个接口要好。还是一个降低类之间的耦合度的意思,从这儿我们看出,其实设计模式就是一个软件的设计思想,从大软件架构出发,为了升级和维护方便。所以上文中多次出现:降低依赖,降低耦合。 5、迪米特法则(最少知道原则)(Demeter Principle) 为什么叫最少知道原则,就是说:一个实体应当尽量少的与其他实体之间发生相互作用,使得系统功能模块相对独立。 6、合成复用原则(Composite Reuse Principle) 原则是尽量使用合成/聚合的方式,而不是使用继承。
书籍目录 目录 第1章基本概念 1 1.1什么是设计模式 2 1.2设计模式的作用 3 1.3GRASP模式的分类 4 1.4GoF设计模式的分类 4 1.5模式的学习阶段 6 第2章负责任地设计对象——GRASP 9 2.1InformationExpert(信息专家) 11 2.2Creator(创造者) 13 2.3LowCoupling(低耦合) 14 2.4HighCohesion(高内聚) 15 2.5Controller(控制器) 17 2.6Polymorphism(多态) 18 2.7PureFabrication(纯虚构) 19 2.8Indirection(间接) 20 2.9ProtectedVariations(受保护变化) 21 第3章GoF-CreationalDesignPatterns创建设计模式 23 3.1SimpleFactoryPattern(简单工厂模式) 24 3.1.1定义 24 3.1.2现实例子——国旗生产厂 26 3.1.3C#实例1——电子付款系统 26 3.1.4C#实例2——学校登录系统 29 3.1.5Java实例——手机简单工厂 32 3.1.6优势和缺陷 34 3.1.7应用情景 34 3.2FactoryMethodPattern(工厂方法模式) 35 3.2.1定义 35 3.2.2现实例子——兵工厂 36 3.2.3C#实例——多文档系统 37 3.2.4Java实例——扩展了的手机工厂 41 3.2.5优势和缺陷 44 3.2.6应用情景 44 3.3AbstractFactoryPattern(抽象工厂模式) 45 3.3.1定义 45 3.3.2现实例子——扩展了的兵工厂 48 3.3.3C#实例——大陆生态系统 49 3.3.4Java实例——电脑产品 52 3.3.5优势和缺陷 57 3.3.6应用情景 57 3.4BuilderPattern(建造者模式) 58 3.4.1定义 58 3.4.2现实例子——快餐店 60 3.4.3C#实例——车间造车 61 3.4.4Java实例——建造房屋 65 3.4.5优势和缺陷 69 3.4.6应用情景 70 3.5PrototypePattern(原型模式) 70 3.5.1定义 70 3.5.2现实中的拷贝-粘贴 71 3.5.3C#实例——颜色管理器 72 3.5.4Java实例——简单ToolBar 74 3.5.5ShallowCopy与DeepCopy 76 3.5.6优势和缺陷 82 3.5.7应用情景 82 3.6SingletonPattern(单例模式) 82 3.6.1定义 82 3.6.2现?抵械牡ダ??猈indowsTaskManager 83 3.6.3C#实例——负载均衡控制器 84 3.6.4Java实例——系统日志 86 3.6.5DoubleCheckLocking(双检锁) 89 3.6.6优势和缺陷 93 3.6.7应用情景 93 第4章GoF-StructuralDesignPatterns结构设计模式 95 4.1AdapterPattern(适配器模式) 96 4.1.1定义 96 4.1.2现实中的实例——电脑电源适配器 97 4.1.3C#实例——化学数据银行 98 4.1.4Java实例——清洁系统 102 4.1.5优势和缺陷 104 4.1.6应用情景 104 4.2BridgePattern(桥接模式) 104 4.2.1定义 104 4.2.2现实中的实例——男人的约会 106 4.2.3C#实例——商业对象与数据对象 107 4.2.4Java实例——不同系统的图像处理 112 4.2.5优势和缺陷 114 4.2.6应用情景 115 4.3CompositePattern(组合模式) 115 4.3.1定义 115 4.3.2组合模式的现实应用——资源管理器 117 4.3.3C#实例——图形树状对象结构 118 4.3.4Java实例——文档格式化 121 4.3.5优势和缺陷 124 4.3.6应用情景 125 4.4DecoratorPattern(装饰模式) 125 4.4.1定义 125 4.4.2现实中的装饰模式——相架 126 4.4.3C#实例——图书馆中的项目 127 4.4.4Java实例——自定义JButton 131 4.4.5优势和缺陷 133 4.4.6应用情景 134 4.5FacadePattern(外观模式) 134 4.5.1定义 134 4.5.2现实中的实例——顾客服务员 135 4.5.3C#实例——抵押申请审核 136 4.5.4Java实例——冲茶 139 4.5.5优势和缺陷 143 4.5.6应用情景 143 4.6FlyweightPattern(轻量级模式) 144 4.6.1定义 144 4.6.2实例——中游的四国军棋 146 4.6.3C#实例——文档编辑器 147 4.6.4Java实例——装载图像 151 4.6.5优势和缺陷 154 4.6.6应用情景 154 4.7ProxyPattern(代理模式) 154 4.7.1定义 154 4.7.2几个现实中的实例 156 4.7.3C#实例——数学代理 158 4.7.4Java实例——Socket回声 160 4.7.5优势和缺陷 165 4.7.6应用情景 165 第5章GoF-BehavioralDesignPatterns行为设计模式 167 5.1ChainofResponsibility(责任链模式) 168 5.1.1定义 168 5.1.2现实中的实例——军情的传递 169 5.1.3C#实例——采购分级审批 170 5.1.4Java实例——智能大厦安全系统 174 5.1.5优势和缺陷 178 5.1.6应用情景 178 5.2CommandPattern(命令模式) 179 5.2.1定义 179 5.2.2现实中的实例——餐馆订菜 180 5.2.3C#实例——简单计算器 181 5.2.4Java实例——总开关 185 5.2.5优势和缺陷 189 5.2.6应用情景 189 5.3InterpreterPattern(解释器模式) 190 5.3.1定义 190 5.3.2现实示例——音乐符号 192 5.3.3C#实例——中国金钱大写转换 192 5.3.4Java实例——自定义程序解释器 197 5.3.5优势和缺陷 204 5.3.6应用情景 205 5.4IteratorPattern(迭代器模式) 205 5.4.1定义 205 5.4.2现实示例——电视节目选择器 206 5.4.3C#实例——遍历例子 207 5.4.4Java实例——两个迭代器 211 5.4.5优势和缺陷 213 5.4.6应用情景 214 5.5MediatorPattern(中介者模式) 214 5.5.1定义 214 5.5.2现实示例——机场控制塔 215 5.5.3C#实例——聊天室 216 5.5.4Java实例——多线程通信 220 5.5.5优势和缺陷 223 5.5.6应用情景 223 5.6MementoPattern(备忘录模式) 223 5.6.1定义 223 5.6.2现实示例——音响均衡器 226 5.6.3C#实例——销售目标 226 5.6.4Java实例——多次Undo(取消)操作 231 5.6.5优势和缺陷 236 5.6.6应用情景 236 5.7ObserverPattern(观察者模式) 236 5.7.1定义 236 5.7.2现实例子——拉登现身了 238 5.7.3C#实例——猫和老鼠 238 5.7.4C#实例——股票变化 241 5.7.5Java实例——监控系统 245 5.7.6优势和缺陷 248 5.7.7应用情景 248 5.8StatePattern(状态模式) 248 5.8.1定义 248 5.8.2现实例子——心情好坏 250 5.8.3C#实例——账户分类 250 5.8.4Java实例——汽车的变速档 258 5.8.5优势和缺陷 261 5.8.6应用情景 261 5.9StrategyPattern(策略模式) 261 5.9.1定义 261 5.9.2现实例子——去机场的策略 263 5.9.3C#实例——排序方法 263 5.9.4Java实例——多格式输出 266 5.9.5优势和缺陷 272 5.9.6应用情景 272 5.10TemplateMethodPattern(模板方法模式) 272 5.10.1定义 272 5.10.2现实例子——厨师烹调 274 5.10.3C#实例——数据库连接模板 274 5.10.4Java实例——冒泡排序模板 277 5.10.5优势和缺陷 280 5.10.6应用情景 280 5.11VisitorPattern(访问者模式) 280 5.11.1定义 280 5.11.2现实例子——收银员收银计费 282 5.11.3C#实例——人事评估 283 5.11.4Java实例——维修工程师检查车辆 287 5.11.5优势和缺陷 291 5.11.6应用情??291 第6章模式的综合应用 293 6.1Java实例——扩展的日志记录器 294 6.2C#实例——存储分析器 298 6.3用模式生成程序架构 316 附录1自测题 321 附录2自测题答案 331 参考文献 337
总体来说设计模式分为三大类: 创建模式,共五种:工厂方法模式、抽象工厂模式、单例模式、建造者模式原型模式。 结构模式,共七种:适配器模式、装饰器模式、代理模式、外观模式、桥接模式、组合模式、享元模式。 行为模式,共十一种:策略模式、模板方法模式、观察者模式、迭代子模式、责任链模式、命令模式、备忘录模式、状态模式、访问者模式、中介者模式、解释器模式。 二、设计模式的六大原则 1、开闭原则(Open Close Principle) 开闭原则就是说对扩展开放,对修改关闭。在程序需要进行拓展的时候,不能去修改原有的代码,实现一个热插拔的效果。所以一句话概括就是:为了使程序的扩展性好,易于维护和升级。想要达到这样的效果,我们需要使用接口和抽象类,后面的具体设计中我们会提到这点。 2、里氏代换原则(Liskov Substitution Principle) 里氏代换原则(Liskov Substitution Principle LSP)面向对象设计的基本原则之一。 里氏代换原则中说,任何基类可以出现的地方,子类一定可以出现。 LSP是继承复用的基石,只有当衍生类可以替换掉基类,软件单位的功能不受到影响时,基类才能真正被复用,而衍生类也能够在基类的基础上增加新的行为。里氏代换原则是对“开-闭”原则的补充。实现“开-闭”原则的关键步骤就是抽象化。而基类与子类的继承关系就是抽象化的具体实现,所以里氏代换原则是对实现抽象化的具体步骤的规范。—— From Baidu 百科 3、依赖倒转原则(Dependence Inversion Principle) 这个是开闭原则的基础,具体内容:真对接口编程,依赖于抽象而不依赖于具体。 4、接口隔离原则(Interface Segregation Principle) 这个原则的意思是:使用多个隔离的接口,比使用单个接口要好。还是一个降低类之间的耦合度的意思,从这儿我们看出,其实设计模式就是一个软件的设计思想,从大软件架构出发,为了升级和维护方便。所以上文中多次出现:降低依赖,降低耦合。 5、迪米特法则(最少知道原则)(Demeter Principle) 为什么叫最少知道原则,就是说:一个实体应当尽量少的与其他实体之间发生相互作用,使得系统功能模块相对独立。 6、合成复用原则(Composite Reuse Principle) 原则是尽量使用合成/聚合的方式,而不是使用继承。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值