前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >设计模式之开闭原则C++实现

设计模式之开闭原则C++实现

作者头像
用户9831583
发布2022-06-16 14:33:16
3760
发布2022-06-16 14:33:16
举报
文章被收录于专栏:码出名企路

开闭原则: 当应用的需求改变时,在不修改软件实体的源代码或者二进制代码的前提下,可以扩展模块的功能,使其满足新的需求。

实现方式:“抽象约束、封装变化”,通过接口或者抽象类为软件实体定义一个相对稳定的抽象层,而将相同的可变因素封装在相同的具体实现类中。

具体示例:

设计一个图书售卖系统,UML类图如下

第一步:定义父类 book.h

代码语言:javascript
复制
#pragma once
#include <iostream>
using namespace std;
#include <cstring>

//对外接口
/*
1、接口类中不应该声明成员变量,静态变量。

2、可以声明静态常量作为接口的返回值状态,需要在对应的cpp中定义并初始化,
    访问时需要使用"接口类型::静态常量名"访问

2、定义的接口方法使用virtual 修饰符 和 “=0” 修饰,表示该方法是纯虚的。

3、因为接口类是无法创建对象的,所以不应该编写构造函数和析构函数*/

class Book
{
    public:修改后的UML类图        //书籍名称
        virtual string getname()=0;
        //书籍价格
        virtual int getprice()=0;
        //书籍作者
        virtual string getauthor()=0;

};

第二步:定义小说类novelbook.h

代码语言:javascript
复制
#include "book.h"
//子类
class NovelBook:public Book
{  
  public:
      NovelBook(){}

      NovelBook(string _name, int _price, string _author)
      {
          this->book_name=_name;
          this->book_price=_price;
          this->book_author=_author;
      }

      ~NovelBook(){}

      //对接口函数的实现
      string getname(){return this->book_name;}
      int getprice(){return this->book_price;}
      string getauthor(){return this->book_author;}

  //private://这样的话子类用不了了
  public:
      string book_name;
      int book_price;
      string book_author;
};

第三步:定义主函数main.cpp

代码语言:javascript
复制
#include "offnovelbook.h"
#include "computebook.h"
#include <list>

class BookStore
{
    public:
        BookStore(){}
        ~BookStore(){}
  
        void get()
       {  
            for (int i=0;i<4;i++)
                 Novel_bookList.push_back(b1[i]);
           
       }
      
       void play()
       {  

        list<NovelBook>::iterator item1;
              
         for (item1= Novel_bookList.begin();item1!= Novel_bookList.end();item1++)
         {
              book_name=item1->getname();
              book_price=item1->getprice();
              book_author=item1->getauthor();
              cout<<"name "<<book_name<<" price "<<book_price
                <<" author "<<book_author<<endl;
         }
                   cout<<"************************"<<endl;
        
          }
    
   private:
    string book_name;
     int book_price;
    string book_author;

       list<NovelBook> Novel_bookList;
     NovelBook b1[4]={
        NovelBook("天龙八部",3200,"金庸"),
       NovelBook("巴黎圣母院",5600,"雨果"),
       NovelBook("悲惨世界",3500,"雨果"),
       NovelBook("金瓶梅",4300,"兰陵笑笑生")
    };

};

int main()
{  
    BookStore bbook;
 
     bbook.get();
     bbook.play();

    return 0;
}

结果显示:

项目投产了, 书籍正常销售出去, 书店赢利很多,此时,老板为了促销,实行全部书籍打9折销售。

此时,有如下三种方法可以解决这个问题:

1)修改接口 book.h:在Book上新增加一个方法getOffPrice(), 专门用于进行打折处理, 所有的实现类实现该方法。修改的后果是, 实现类NovelBook要修改, BookStore中的方法也修改, 同时Book作为接口应该是稳定且可靠的, 不应该经常发生变化, 否则接口作为契约的作用就失去了效能。

2)修改实现类 novelbook.h:修改NovelBook类中的方法, 直接在getPrice()中实现打折处理, 通过class文件替换的方式可以完成部分业务变化。但是该方法还是有缺陷的---例如采购书籍人员也是要看价格的, 由于该方法已经实现了打折处理价格, 因此采购人员看到的也是打折后的价格, 会因信息不对称而出现决策失误的情况。

3)通过扩展实现变化:增加一个子类OffNovelBook, 覆写getPrice方法, 高层次的模块, 通过OffNovelBook类产生新的对象, 完成业务变化对系统的最小化开发。

因此,第三种方案修改,修改后的UML类图如下

第四步:增加一个offnovelbook.h

代码语言:javascript
复制
#include "novelbook.h"
//增加一个打折销售类
class OffNovelBook:public NovelBook
{
    public:
        OffNovelBook(string _name, int _price, string _author )
        {
            this->book_name=_name;
            this->book_price=_price;
            this->book_author=_author;
        }
        //打折价格,覆盖基类的
        int getprice()
        { 
            off_book_price=NovelBook::getprice();
            off_book_price=off_book_price*90/100;
            return off_book_price;
        }

    private:
        int off_book_price;
};

第五步:在main.cpp中添加实现

代码语言:javascript
复制
//void get()中添加:
for (int i=0;i<4;i++)
     OffNovel_bookList.push_back(b2[i]);
 
 //void play()中添加:
      list<OffNovelBook>::iterator item2;
              
         for (item2= OffNovel_bookList.begin();item2!=OffNovel_bookList.end();item2++)
         {
              book_name=item2->getname();
              book_price=item2->getprice();
              book_author=item2->getauthor();
              cout<<"name "<<book_name<<" price "<<book_price
                <<" author "<<book_author<<endl;
         }
 //添加变量
     list<OffNovelBook> OffNovel_bookList;
     OffNovelBook b2[4]={
        OffNovelBook("天龙八部",3200,"金庸"),
       OffNovelBook("巴黎圣母院",5600,"雨果"),
       OffNovelBook("悲惨世界",3500,"雨果"),
       OffNovelBook("金瓶梅",4300,"兰陵笑笑生")
    };

结果显示:

这次老板开心了,又赚了一大笔。可是又过了一段时间,项目需求变化了,老板新进了计算机类的书籍,但是计算机书籍还有很多种,有编程语言,数据库需要分类。

熟悉了以上设计原则后,画出总UML类图如下

第六步:添加虚Pcomputebook.h

代码语言:javascript
复制
#include "book.h"
//增加计算机类 接口函数
class PcomputeBook:public Book
{  
    public:
        //有编程的,数据库的,新加的接口
        virtual string getscope()=0;
};

第七步:添加实现computebook.h

代码语言:javascript
复制
#include "Pcomputebook.h"

//子类
class ComputeBook:public PcomputeBook
{  
    public:
        ComputeBook(){}

       ComputeBook(string _name, int _price, string _author,string _scope)
        {
            this->book_name=_name;
            this->book_price=_price;
            this->book_author=_author;
            this->book_scope=_scope;
        }
       // ~ComputelBook(){}
        //对接口函数的实现
        string getname(){return this->book_name;}
        int getprice(){return this->book_price;}
        string getauthor(){return this->book_author;}
        string getscope(){return this->book_scope;}
    //private://这样的话子类用不了了
    public:
        string book_name;
        int book_price;
        string book_author;
        string book_scope;

};

第八步:添加main.cpp实现

代码语言:javascript
复制
//void get()
for (int i=0;i<4;i++)
                 Compute_bookList.push_back(b3[i]);
 //void play()       
        for (item3= Compute_bookList.begin();item3!=Compute_bookList.end();item3++)
         {
              book_name=item3->getname();
              book_price=item3->getprice();
              book_author=item3->getauthor();
              book_scope=item3->getscope();
              cout<<"name "<<book_name<<" price "<<book_price
                <<" author "<<book_author<<" scope "<<book_scope<<endl;
         }
//
   string book_scope;
       list<ComputeBook> Compute_bookList;
     ComputeBook b3[4]={
        ComputeBook("C++",3200,"金庸","编程类"),
       ComputeBook("C",5600,"雨果","编程类"),
       ComputeBook("Java",3500,"雨果","编程类"),
       ComputeBook("Python",4300,"兰陵笑笑生","编程类")

结果显示:

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2020-02-13,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 码出名企路 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档