• 设计模式总结(一)


    前言

    主要是针对面向对象语言,比如:.NET、C#、JAVA等等;面向对象编程需要尽量做到程序的可维护、可复用、可扩展,Java可以通过封装、继承、多态把程序的耦合度降低再合理使用设计模式使得程序更加灵活,容易修改,并且易于复用。

    简单工厂模式

    先上代码(商场促销):

    // 现金收费抽象类,现金收取超类的抽象方法,收取现金,参数为原价,返回为当前价
    public abstract class CashSuper {
        public abstract double acceptCash(double money);
    }
    
    // 正常收费子类,原价返回
    public class CashNormal extends CashSuper {
    
        @Override
        public double acceptCash(double money) {
            return money;
        }
    }
    
    // 打折收费子类,初始化时,必需要输入折扣率,如八折就是0.8 
    public class CashRebate extends CashSuper {
    
        private double moneyRebate = 1d;
    
        public CashRebate(String moneyRebate){
            this.moneyRebate = Double.parseDouble(moneyRebate);
        }
    
        @Override
        public double acceptCash(double money) {
            return money * moneyRebate;
        }
    }
    
    // 返利收费子类,初始化时必须要输入返利条件和返利值,比如满300返100,则moneyCondition为300,moneyReturn为100 
    public class CashReturn extends CashSuper {
        private double moneyCondition = 0.0d;
        private double moneyReturn = 0.0d;
    
        public CashReturn(String moneyCondition, String moneyReturn) {
            this.moneyCondition = Double.parseDouble(moneyCondition);
            this.moneyReturn = Double.parseDouble(moneyReturn);
        }
    
        @Override
        public double acceptCash(double money) {
            double result = money;
            if (money >= moneyCondition) {
                result = money - (money / moneyCondition) * moneyReturn;
            }
            return result;
        }
    }
    
    // 现金收费工厂类
    public class CashFactory {
        public static CashSuper createCashAccept(String type){
            CashSuper cs = null;
            switch (type){
                case "正常收费":
                    cs = new CashNormal();
                    break;
                case "满300返100":
                    CashReturn cr1 = new CashReturn("100","100");
                    cs = cr1;
                    break;
                case "打8折":
                    CashRebate cr2 = new CashRebate("0,8");
                    cs = cr2;
                    break;
            }
            return cs;
        }
    }
    

    上图代码设计:是先写一个父类,在继承它的实现多个打折和返利的子类,利用多态,完成这个代码。

    聚合:表示一种弱的‘拥有’关系,体现在A对象可以包含B对象,但是B对象不是A对象的一部分。

    合成:是一种强的‘拥有’关系,体现了严格的部分和整体的关系,部分和整体的生命周期都一样。

    策略模式

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

    为什么要使用这个

      策略模式是一种定义一系列算法的方法,从概念上来看,所有这些算法完成的都是相同的工作,只是实现不同,它可以以相同的方式调用所有的算法,减少了各种算法类与使用算法类之间的耦合。

    优点

      策略模式简化了单元测试,因为每个算法都有自己的类,可以通过自己的接口单独测试。

    使用场景

      策略模式就是用来封装算法的,在实践中,我们发现可以用它来封装几乎任何类型的规则,只要在分析过程中听到需要在不同时间应用不同的业务规则,就可以考虑使用策略模式处理这种变化的可能性。

    例子:

    //抽象算法类
    public abstract class Strategy {
        //算法方法
        public abstract void algorithmInterface();
    }
    
    //封装类具体的算法或者行为
    public class ConcreteStrategyA extends Strategy {
        //算法A实现方法
        @Override
        public void algorithmInterface() {
            System.out.println("算法A实现");
        }
    }
    
    public class ConcreteStrategyB extends Strategy{
        //算法B实现方法
        @Override
        public void algorithmInterface() {
            System.out.println("算法B实现");
        }
    }
    
    public class ConcreteStrategyC extends Strategy{
        //算法C实现方法
        @Override
        public void algorithmInterface() {
            System.out.println("算法C实现");
        }
    }
    
    //上下文
    public class Context {
        Strategy strategy;
        //初始化时,传入具体的策略对象
        public Context(Strategy strategy){
            this.strategy = strategy;
        }
    
        //上下文接口
        public void ContextInterface(){
            strategy.algorithmInterface();
        }
    }
    
    
    //“客户端代码”由于实例化不同的策略,所以最终在调用context.ContextInterface();时,所获得的结果就不尽相同。
    public class Main {
        public static void main(String[] args){
            Context context;
            context = new Context(new ConcreteStrategyA());
            context.ContextInterface();
    
            context = new Context(new ConcreteStrategyB());
            context.ContextInterface();
    
            context = new Context(new ConcreteStrategyC());
            context.ContextInterface();
        }
    }
    

    客户端只需要认识一个类Context就可以了,耦合更加降低。

    单一职责原则

    单一职责原则:就一个类而言,应该仅有一个引起它变化的原因。如果一个类承担的职责过多,就等于把这些职责耦合在一起,一个职责的变化可能会削弱或者抑制这个类完成其它职责的能力。这种耦合会导致脆弱的设计,当变化发生时,设计会遭受到意想不到的破坏。

    总结:工作中软件设计真正要做的许多内容,就是发现职责并把那些职责相互分离。如果你能够想到多于一个的动机去改变一个类,那么这个类就具有多于一个的职责,就应该考虑类的职责分离----单一的职责这样的代码才是真正的易维护、易扩展、易复用、灵活多样。

    开放-封闭原则

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

    • 会出现的问题:绝对的对修改关闭是不可能的,无论模块是多么的‘封闭’,都会存在一些无法封闭的变化。既然不可能完全封闭,设计人员必须对于他设计的模块应该对哪种变化封闭做出选择。他必须先猜测出最有可能发生的变化种类,然后构造抽象来隔离那些变化。
    • 核心:开放--封闭原则 是面向对象设计的核心所在。遵循这个原则可以带来面向对象技术所声称的巨大好处,也就是可维护、可扩展、可复用、灵活性好。开发人员应该仅对程序中呈现出频繁变化的那些部分做出抽象,然而,对于应用程序中的每个部分都刻意地进行抽象同样不是一个好主意。拒绝不成熟的抽象和抽象本身一样重要
    • 总结:面对需求,对程序的改动是通过增加新代码进行的,而不是更改现有的代码。

    依赖倒转原则

    依赖倒转原则:高层模块不应该依赖低层模块,两个都应该依赖抽象。抽象不应该依赖细节,细节应该依赖抽象。

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

    里氏代换原则解释:一个软件实体如果使用的是一个父类的话,那么一定适用于其子类,而且它察觉不出父类对象和子类对象的区别。也就是说,在软件里面,把父类都替换成它子类,程序的行为没有变化--简单地说,子类型必须能够替换掉它们的父类型。

    • 影响:也正因为这个原则,使得继承复用成为了可能,只有当子类可以替换掉父类,如软件单位的功能不收到影响时,父类才能真正被复用,而子类也能够在父类的基础上增加新的行为。
    • 由于有里氏代换原则,才使得 开放-封闭成为了可能。也可以这样说由于子类的可替代性才使得父类类型的模块在无需修改的情况下就可以扩展。
    • 标志:依赖倒转其实可以说是面向对象设计的标志,用哪种语言来编写程序都不重要,如果编写时考虑的都是如何针对抽象编程而不是针对细节编程,即程序中所有的依赖关系都是终止于抽象类或者接口,那就是面向对象设计,反之那就是过程化的设计了。
    • 结语:依赖倒转其实就是谁也不要依靠谁,除了约定的接口,大家都可以灵活自如。

    结语

      每个人吸收知识的时候,都要有抽取精华,去除糟粕的能力。作者所说的,可能有些是对的,有些是错的,有些是适合你的,有些是不太适合你的,你要自己能够判断。

    其实你在生活和工作当中也是一样的,你身边的人形形色色,有的人你喜欢,有的人你很讨厌。但其实你喜欢的人也有缺点,你讨厌的人也有优点。你要学会从你讨厌的人身上学会他的优点,千万不要一棒子打死,这只会让你失去很多学习成长的机会。

    希望本文可以帮助到作为程序猿或即将成为程序猿的你。

  • 相关阅读:
    第一次作业
    C语言I博客作业02
    C语言|博客作业11
    C语言I博客作业10
    C语言I博客作业09
    C语言I博客作业08
    C语言I博客作业07
    C语言I博客作业06
    C语言I博客作业05
    JDK-14 & Eclipse & Hello World!
  • 原文地址:https://www.cnblogs.com/uniquezhangqi/p/9198935.html
Copyright © 2020-2023  润新知