Các thực thể phần mềm nhƣ các lớp, module, hàm... nên đƣợc xây dựng theo hướng mở cho việc mở rộng nhưng đóng đối với việc sửa đổi.
Trong một dự án phần mềm thường bao gồm các thực thể khác nhau. Các thực thể này không tách biệt nhau mà có sự gắn kết, tương tác với nhau theo những cách thức trong những tình huống nhất định. Một trong những yêu cầu trong thiết kế phần mềm là phải tính đến khả năng bảo trì, mở rộng của phần mềm sau này, đáp ứng các nhu cầu và điều kiện thay đổi. Tuy nhiên, một bất lợi cho sự gắn kết chặt chẽ giữa các thực thể phần mềm là, khi ta nâng cấp, mở rộng một thực thể nào đó, thì các thực thể liên quan cũng phải đƣợc nâng cấp, mở rộng cho phù hợp. Với sự phát triển nhanh chóng của việc ứng dụng công nghệ thông tin và các điều kiện thay đổi, việc nâng cấp, mở rộng phần mềm sẽ diễn ra là điều khó tránh khỏi.
Do đó để có thể bảo trì, nâng cấp phần mềm đƣợc dễ dàng, trong quá trình phân tích thiết kế, các kỹ sƣ phần mềm cần xây dựng theo nguyên lý đóng mở. Nghĩa là cần xây dựng lên một kiến trúc phần mềm sao cho nó có thể mở rộng, thay đổi hay thêm
tuy nhiên hạn chế tối đa việc thay đổi các thực thể đã tồn tại, nhất là việc sửa đổi mã nguồn của phần mềm trước đó. Hay nói cách khác, không nên tác động vào mã nguồn của các thực thể đã tồn tại.
Để minh họa cho nguyên lý trên, ta có thể xét ví dụ đơn giản sau: giả sử chương trình ban đầu thực hiện chức năng vẽ các đối tượng hình học là đường thẳng và hình chữ nhật. Sử dụng phương pháp lập trình cấu trúc, ta có thể mã hóa đoạn chương trình nhƣ sau:
public enum ShapeType{ LINE, RECTANGLE } public abstract class Shape {
public abstract ShapeType getType();
}
public class Line: Shape{
public override ShapeType getType(){
return ShapeType.LINE;
}
public void drawLine(){
// Các lệnh vẽ đoạn thẳng }
}
public class Rectangle: Shape{
public override ShapeType getType(){
return ShapeType.RECTANGLE;
}
public void drawRectangle(){
// Các lệnh vẽ hình chữ nhật }
}
public void draw(ArrayList shapeList){
Line objLine;
Rectangle objRectangle;
foreach (Shape s in shapeList) switch (s.getType()){
case ShapeType.LINE:
objLine = (Line)s;
objLine.drawLine();
break;
case ShapeType.RECTANGLE:
objRectangle = (Rectangle)s;
objRectangle.drawRectangle();
} }
Đoạn chương trình trên đã đáp ứng được yêu cầu là vẽ đường thẳng và đường tròn ra màn hình. Bây giờ giả sử cần nâng cấp, mở rộng chương trình, giả sử ta thêm vào chương trình đoạn mã vẽ đường tròn. Khi đó ta phải chỉnh sửa lại hàm draw, bằng cách trong khối lệnh switch, ta thêm vào một trường hợp của đường tròn. Tuy nhiên trong nhiều trường hợp, việc chỉnh sửa hàm draw này dẫn đến việc phải chỉnh sửa các hàm, thực thể khác liên quan. Do đó dẫn đến việc vi phạm nguyên lý đóng mở.
Để đoạn chương trình trên có thể tuân thủ nguyên lý đóng mở, chúng ta sẽ sử dụng tính đa hình của lập trình hướng đối tượng. Và chương trình trên sẽ được điều chỉnh lại nhƣ sau:
public abstract class Shape{
public abstract void draw();
}
public class Line: Shape{
public override void draw(){
// Các lệnh vẽ đoạn thẳng }
}
public class Rectangle: Shape{
public override void draw(){
// Các lệnh vẽ hình chữ nhật }
}
class Circle: Shape{
public override void draw(){
// Các lệnh vẽ hình tròn }
}
public void draw(ArrayList shapeList){
foreach (Shape s in shapeList) s.draw();
}
Trong đoạn chương trình trên, khi cần thêm một hình mới vào, ta chỉ cần thêm lớp đối tƣợng cho hình đó thừa kế từ lớp trừu tƣợng Shape mà không cần phải chỉnh sửa lại hàm draw.
Việc thiết kế phần mềm cần phải đƣợc tuân thủ nguyên lý đóng mở. Tuy nhiên trong đó, không phải lúc nào các thực thể phần mềm cũng tuân thủ nguyên lý. Mục tiêu của thiết kế là tối ƣu việc tuân thủ nguyên lý thiết kế, cân đối giữa việc tuân thủ
tăng khả năng tuân thủ nguyên lý đóng mở của các thực thể phần mềm, đó là tính đóng gói. Các đối tƣợng quản lý và chịu trách nhiệm trên các thông tin của mình. Do đó hạn chế khả năng kết dính giữa các đối tượng. Trong trường hợp tối ưu, các thuộc tính của đối tƣợng đƣợc đặt là private. Khi đó việc thay đổi các thuộc tính của đối tƣợng chỉ đƣợc thông qua các thao tác của chính các đối tƣợng đó mà các đối tƣợng khác không thể truy cấp đƣợc các thuộc tính này.