设计模式(四)之开放封闭原则

简介: 开放封闭原则:软件实体(类、模块、函数等等)应该可以扩展,但是不可以修改。也就是如果需求发生变化导致程序中多个依赖模块都发生了级联的改动,就说明这个程序是有问题的,程序变得相对脆弱、无法重用。开放封闭原则就相对的解决了这个问题,它强调的是你设计的模块应该从不改变(绝对不改变是不可能的,只能相对少改动)。当需求变化时,你可以通过添加新的代码来扩展这个模块的行为,而不去更改那些已经存在的可以工作的代码。

QQ图片20220424001429.jpg

开放封闭原则:


软件实体(类、模块、函数等等)应该可以扩展,但是不可以修改。


也就是如果需求发生变化导致程序中多个依赖模块都发生了级联的改动,就说明这个程序是有问题的,程序变得相对脆弱、无法重用。开放封闭原则就相对的解决了这个问题,它强调的是你设计的模块应该从不改变(绝对不改变是不可能的,只能相对少改动)。当需求变化时,你可以通过添加新的代码来扩展这个模块的行为,而不去更改那些已经存在的可以工作的代码。


举一个简单的开放封闭原则的例子:书店售书打折。


书店周年庆打折售书,40块以上的书打7折,40块以下的书打8折。那我们如何使用开放封闭原则来实现打折售书的这个情况呢。


首先,我们将正常的售书程序写出来。


Program.cs


using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
/// <summary>
/// 开放封闭原则
/// </summary>
namespace OpenAndClosed
{
    /// <summary>
    /// 主程序
    /// </summary>
    class Program
    {
        public static List<Book> bookList =  new List<Book>();
        static void Main(string[] args)
        {
            if (bookList.Count == 0)
            {
                bookList.Add(new Book("刘同", "谁的青春不迷茫", 35));
                bookList.Add(new Book("刘慈欣", "三体", 55));
                bookList.Add(new Book("王小波", "黄金时代", 41));
            }
            for (int i = 0; i < bookList.Count; i++)
            {
                Console.WriteLine("作者:"+ book.GetAuthor() +"; 书名:"+ book.GetBookName() + "; 价格:"+ book.GetPrice(bookList[i].price));            }
            Console.ReadLine();
        }
    }
}


书类:book.cs


using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace OpenAndClosed
{
    /// <summary>
    /// 书的类
    /// </summary>
    public class Book
    {
        /// <summary>
        /// 作者
        /// </summary>
        public string author;
        /// <summary>
        /// 书名
        /// </summary>
        public string bookName;
        /// <summary>
        /// 价格
        /// </summary>
        public double price;
        /// <summary>
        /// 构造函数
        /// </summary>
        /// <param name="author">作者</param>
        /// <param name="bookName">书名</param>
        /// <param name="price">价钱</param>
        public Book(string author,string bookName, double price)
        {
            this.author = author;
            this.bookName = bookName;
            this.price = price;
        }
        /// <summary>
        /// 获取作者
        /// </summary>
        /// <returns></returns>
        public string GetAuthor()
        {
            return author;
        }
        /// <summary>
        /// 获取作者
        /// </summary>
        /// <returns></returns>
        public double GetPrice(double pri)
        {
            price = pri;
            return price;
        }        /// <summary>
        /// 获取作者
        /// </summary>
        /// <returns></returns>
        public string GetBookName()
        {
            return bookName;
        }
    }
}


现在来考虑,如何实现上边所说的打折。


第一种方法:在主函数中(program.cs)判断价格,符合要求打折。


但是这显然不合适,如果打折的需求变得更加复杂,或者以后需要增加积分返点之类的功能,这部分代码就变得相当的臃肿。


第二种方法:在实现类(Book.cs)中判断价格,符合要求打折。


这个很明显的违反了开放-封闭原则。

如果修改这个类中getPrice方法,那摩一定要在这个方法中进行价格判断,就算把每个打折的算法封装成多个子类,每次增加或者修改打折算法的时候,都需要去修改这个方法中的判断。


第三种方法:定义一个类,继承Book.cs,再类中覆盖父类中的getPrice方法。


这样我们就可以不修改Book类中getPrice及主函数的代码来实现打折的功能。

下边是使用开放封闭原则来实现的代码:


主文件:program.cs  :改为实例化book类的子类discount


using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
/// <summary>
/// 开放封闭原则
/// </summary>
namespace OpenAndClosed
{
    /// <summary>
    /// 主程序
    /// </summary>
    class Program
    {
        public static List<Book> bookList =  new List<Book>();
        static void Main(string[] args)
        {
            if (bookList.Count == 0)
            {
                bookList.Add(new Book("刘同", "谁的青春不迷茫", 35));
                bookList.Add(new Book("刘慈欣", "三体", 55));
                bookList.Add(new Book("王小波", "黄金时代", 41));
            }
            // Book book = null;
            Discount discount = null;
            for (int i = 0; i < bookList.Count; i++)
            {
                // 将此处修改为实例化子类
                //book = new Book(bookList[i].author,bookList[i].bookName,bookList[i].price);
                discount = new Discount(bookList[i].author, bookList[i].bookName, bookList[i].price);
                // book = new Book(bookList[i].author,bookList[i].bookName,bookList[i].price);
                Console.WriteLine("作者:"+ discount.GetAuthor() +"; 书名:"+ discount.GetBookName() + "; 价格:"+ discount.GetPrice(bookList[i].price));
            }
            Console.ReadLine();
        }
    }
}


Book.cs 书类(未做修改)


using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace OpenAndClosed
{
    /// <summary>
    /// 书的类
    /// </summary>
    public class Book
    {
        /// <summary>
        /// 作者
        /// </summary>
        public string author;
        /// <summary>
        /// 书名
        /// </summary>
        public string bookName;
        /// <summary>
        /// 价格
        /// </summary>
        public double price;
        /// <summary>
        /// 构造函数
        /// </summary>
        /// <param name="author">作者</param>
        /// <param name="bookName">书名</param>
        /// <param name="price">价钱</param>
        public Book(string author,string bookName, double price)
        {
            this.author = author;
            this.bookName = bookName;
            this.price = price;
        }
        /// <summary>
        /// 获取作者
        /// </summary>
        /// <returns></returns>
        public string GetAuthor()
        {
            return author;
        }
        /// <summary>
        /// 获取作者
        /// </summary>
        /// <returns></returns>
        public double GetPrice(double pri)
        {
            price = pri;
            return price;
        }
        /// <summary>
        /// 获取作者
        /// </summary>
        /// <returns></returns>
        public string GetBookName()
        {
            return bookName;
        }
    }
}


Discount.cs价格打折文件,继承book.cs(book.cs的扩展)


using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace OpenAndClosed
{
    public class Discount : Book
    {
        /// <summary>
        /// 作者
        /// </summary>
        public static string author;
        /// <summary>
        /// 书名
        /// </summary>
        public static string bookName;
        /// <summary>
        /// 价格
        /// </summary>
        public static double price;
        /// <summary>
        /// 构造函数
        /// </summary>
        /// <param name="author">作者</param>
        /// <param name="bookName">书名</param>
        /// <param name="price">价钱</param>
        public Discount(string autho, string bookNam, double pric): base(author, bookName, price)
        {
            price = pric;
            author = autho;
            bookName = bookNam;
        }
        public double GetPrice(double pri)
        {
            double total;
            Strategy stra;
            if (price > 40)
            {
                stra = new Strategy(new seven(), price);
            }
            else if (price < 40)
            {
                stra = new Strategy(new eight(), price);
            }
            else
            {
                stra = new Strategy(new Normal(), price);
            }
            total = stra.returnDouble();
            return total;
        }
    }
}


策略类:Strategy.cs


using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace OpenAndClosed
{
    public class Strategy
    {
        public IBook ibook = null;
        public double price;
        public Strategy(IBook book, double price)
        {
            ibook = book;
            this.price = price;
        }
        public double returnDouble()
        {
            return ibook.getBookPrice(price);
        }
    }
}


基类:IBook.cs


using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace OpenAndClosed
{
    public interface IBook
    {
        double getBookPrice(double price);
    }
}


子类:八折类:eight.cs


using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace OpenAndClosed
{
    public class eight:IBook
    {
        public double getBookPrice(double price)
        {
            return price * 0.8;
        }
    }
}


七折类:seven.cs


using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace OpenAndClosed
{
    public class seven:IBook
    {
        public double getBookPrice(double price)
        {
            return price * 0.7;
        }
    }
}


正常价格类:Normal.cs


using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace OpenAndClosed
{
    public class Normal:IBook
    {
        public double getBookPrice(double price)
        {
            return price;
        }
    }
}


这里使用开放封闭原则的话,就是增加了一个打折类discount.cs,继承自Book类,是book类的扩展。在整改调用,调用的时候调用子类的对象就行了。代码中都有体现。注意一下就好。


剩下的我结合之前看过的策略模式,定义了一个策略类,将打折算法封装成一个算法家族。为以后再次增加新的打折算法提供便利。


开放封闭原则,是最为重要的设计原则,里式替换原则和合成/聚合复用原则为开放-封闭原则提供保证。


可以通过模板方法模式和策略模式进行重构,实现对修改封闭,对扩展开放的设计思路。


封装变化,是实现开放封闭原则的重要手段,对于经常发生变化的状态,一般将其封装为一个抽象,例如上边例子中的IBook接口。


拒绝滥用抽象,只将经常变化的部分进行抽象。


最后,放上设计六大设计原则


QQ图片20220424001432.png



目录
相关文章
|
3月前
|
设计模式
设计模式七大原则
这篇文章介绍了设计模式中的七大原则,特别强调了单一职责原则,即一个类应该只有一个引起其行为变化的原因,以确保类功能的高内聚和低耦合。
|
3月前
|
设计模式 存储 前端开发
React开发设计模式及原则概念问题之自定义Hooks的作用是什么,自定义Hooks设计时要遵循什么原则呢
React开发设计模式及原则概念问题之自定义Hooks的作用是什么,自定义Hooks设计时要遵循什么原则呢
|
2月前
|
设计模式 Java 关系型数据库
设计模式——设计模式简介和七大原则
设计模式的目的和核心原则、单一职责原则、接口隔离原则、依赖倒转原则、里氏替换原则、开闭原则、迪米特法则、合成复用原则
设计模式——设计模式简介和七大原则
|
5月前
|
设计模式 供应链
设计模式六大原则之迪米特法则
设计模式六大原则之迪米特法则
|
5月前
|
设计模式
设计模式六大原则之依赖倒置原则
设计模式六大原则之依赖倒置原则
|
3月前
|
设计模式 算法 开发者
设计模式问题之最小知识原则(迪米特法则)对代码设计有何影响,如何解决
设计模式问题之最小知识原则(迪米特法则)对代码设计有何影响,如何解决
|
3月前
|
设计模式 前端开发 JavaScript
React开发设计模式及原则概念问题之什么是HOC(Higher-order component),HOC遵循的设计原则都有哪些
React开发设计模式及原则概念问题之什么是HOC(Higher-order component),HOC遵循的设计原则都有哪些
|
3月前
|
设计模式 前端开发 JavaScript
React开发设计模式及原则概念问题之什么是设计模式,单一职责原则如何理解
React开发设计模式及原则概念问题之什么是设计模式,单一职责原则如何理解
|
5月前
|
设计模式 uml
设计模式学习心得之前置知识 UML图看法与六大原则(下)
设计模式学习心得之前置知识 UML图看法与六大原则(下)
37 2
|
5月前
|
设计模式 Java 数据库
深入理解设计模式六大原则
深入理解设计模式六大原则

热门文章

最新文章

  • 1
    《手把手教你》系列基础篇(九十四)-java+ selenium自动化测试-框架设计基础-POM设计模式实现-下篇(详解教程)
    45
  • 2
    C++一分钟之-C++中的设计模式:单例模式
    51
  • 3
    《手把手教你》系列基础篇(九十三)-java+ selenium自动化测试-框架设计基础-POM设计模式实现-上篇(详解教程)
    36
  • 4
    《手把手教你》系列基础篇(九十二)-java+ selenium自动化测试-框架设计基础-POM设计模式简介(详解教程)
    59
  • 5
    Java面试题:结合设计模式与并发工具包实现高效缓存;多线程与内存管理优化实践;并发框架与设计模式在复杂系统中的应用
    54
  • 6
    Java面试题:设计模式在并发编程中的创新应用,Java内存管理与多线程工具类的综合应用,Java并发工具包与并发框架的创新应用
    39
  • 7
    Java面试题:如何使用设计模式优化多线程环境下的资源管理?Java内存模型与并发工具类的协同工作,描述ForkJoinPool的工作机制,并解释其在并行计算中的优势。如何根据任务特性调整线程池参数
    49
  • 8
    Java面试题:请列举三种常用的设计模式,并分别给出在Java中的应用场景?请分析Java内存管理中的主要问题,并提出相应的优化策略?请简述Java多线程编程中的常见问题,并给出解决方案
    102
  • 9
    Java面试题:设计模式如单例模式、工厂模式、观察者模式等在多线程环境下线程安全问题,Java内存模型定义了线程如何与内存交互,包括原子性、可见性、有序性,并发框架提供了更高层次的并发任务处理能力
    74
  • 10
    Go语言设计模式:使用Option模式简化类的初始化
    71