开闭原则

1.定义

   OCP(Open-Closed Principe):一个软件实体应该对扩展开放,对修改关闭。也就是在设计一个模块的时候,应当使这个模块可以在不被修改的前提下被扩展,即实现在不改源代码的情况下改变这个模块的行为。

2.案例

   某图形界面系统提供了各种不同形状的按钮,客户端代码可针对这些按钮进行编程,用户可能会改变需求而使用不同的按钮,原始设计方案如下图所示:

    

3.分析

   由于LoginForm类面向具体对象而进行编程,因此每次更换具体类时不得不修改源代码,而且这些类中方法都没有一个统一的接口,相似功能的方法名称不一致。如果系统要满足开闭原则,需要对按钮类进行抽象化,提取一个抽象类AbstructButton,LoginForm类针对抽象类AbstractButton进行编程,在Java中,可以通过配置文件、DOM解析技术和反射机制将具体类类名存储在配置文件中,再在生成时实例化其对象(后续介绍)。

   使用抽象类AbstractButton后,如果需要矩形按钮(RectangleButton),只需添加一个新的类继承抽象类并修改配置文件OCP.xml即可,无须修改LoginForm类中的代码和AbstractButton的代码,在不修改的前提下扩展系统功能的要求,完全符合开闭原则。配置文件一般都用XmL格式文件或properities格式的属性文件,如图:

  

      注:xml和properties的配置文件都是纯文本文件,可以直接通过VI编辑器或记事本进行编辑,且无需编译,因此在软件开发中,一般不把配置文件的修改认为是对系统源代码的修改。

4.实现

   除了图中四个类,我自己写了个XMLHepler类,用来帮助LoginForm获取按钮名。

      4.1XMLHelper类的设计实现如下:

package OCP;

import java.io.IOException;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;

import org.w3c.dom.Document;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;

public class XMLHepler {

    //帮助loginform获取到按钮名字的类 操作xml文件
    public XMLHepler() {
        // TODO Auto-generated constructor stub
    }
    public String getButtonName()
    {
        DocumentBuilderFactory factory=DocumentBuilderFactory.newInstance();//实例化一个documentbuilderfactory 用来获取documentbuilder
        DocumentBuilder builder=null;
        try {
            builder=factory.newDocumentBuilder();
        }catch(ParserConfigurationException e)
        {
            e.printStackTrace();
        }
        Document document=null;
        try {
            document=builder.parse("OCP.xml");//从指定路径获取xml文件 这里ocp.xml在项目文件夹下
            
        }catch (SAXException e) {
            // TODO: handle exception
            e.printStackTrace();
        }catch(IOException e)
        {
            e.printStackTrace();
        }
        NodeList nList=document.getElementsByTagName("ButtonName");//节点名叫“buttonname” 获取其中的内容
        return nList.item(0).getFirstChild().getNodeValue();//返回其内容
    }
}

      4.2LoginForm类的设计实现如下:

package OCP;
import java.awt.Container;

import javax.swing.*;
public class LoginForm extends JFrame{

    private AbstructButton button=null;
    private XMLHepler xmlHepler=null;
    public LoginForm() {
         setTitle("OCP");
         setVisible(true);
         setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
         setBounds(0,0,200,200);
         setLayout(null);//绝对布局
    }
    //面板容器添加控件
    public void showControl() throws InstantiationException, IllegalAccessException, ClassNotFoundException
    {
        xmlHepler=new XMLHepler();
        String btnName=xmlHepler.getButtonName();
        Container container=getContentPane();
        button=(AbstructButton)Class.forName(btnName).newInstance();//根据名字来实例化对应的按钮
        button.InitButton();
        container.add(button);
    }
    public static void main(String[] args) throws InstantiationException, IllegalAccessException, ClassNotFoundException {
        // TODO Auto-generated method stub
        new LoginForm().showControl();
    }

}

      4.3AbstractButton类设计实现如下:

package OCP;
import javax.swing.*;
public abstract class AbstructButton extends JButton {

    //设计抽象类 满足所有按钮的需求
    public AbstructButton() {
        // TODO Auto-generated constructor stub
    }
    public abstract void InitButton();//抽象方法没有方法体 且子类必须重写
    
}

      4.4RectangleButton类设计实现如下:

package OCP;

import java.awt.Color;

public class RectangleButton extends AbstructButton {

    //实际按钮一 矩形按钮
    public RectangleButton() {
        // TODO Auto-generated constructor stub
    }
    @Override
    public void InitButton()//重写父类方法 初始化一个矩形按钮
    {
        this.setText("矩形按钮");
        this.setBounds(50,50,120,40);
        this.setBackground(Color.CYAN);
    }

}

      4.5CircleButton类设计实现如下:

package OCP;

import java.awt.Color;

public class CircleButton extends AbstructButton{

    //实际按钮二 圆形按钮
    public CircleButton() {
        // TODO Auto-generated constructor stub
    }
    @Override
    public void InitButton()//重写父类方法 圆形按钮初始化
    {
        this.setText("圆形按钮");
        this.setBackground(Color.yellow);
        this.setBounds(50,50,120,40);
    }
}

       4.6运行效果图如下:

     

  

     

            注:本人参考的书籍是清华大学出版社,刘伟主编的《设计模式》。代码中存在的不足,还请多多指教。

原文地址:https://www.cnblogs.com/Juice-Dreamer/p/9825058.html