Java的开放封闭设计原则
开放封闭设计原则是软件开发领域最重要的设计原则之一。它是一组 5 项设计原则的一部分,通常以首字母缩写词“SOLID”为人所知
S - Single Responsibility Principle
O - Open Closed Principle
L - Liskov Substitution Principle
I - Interface Segregation
D - Dependency Inversion
按照 Robert C Martin 的说法,该原则指出软件实体(类、模块、函数)应该对扩展开放,对修改关闭。这意味着一个类应该足够灵活以适应业务需求变化时的变化而不破坏现有代码。因此,依赖类不必更改。这最大限度地减少了测试工作,我们只需要关注新的代码更改。
方法:
基本上有两种实现接口的主要方法:
- 使用继承
- 使用接口和抽象方法
方法一:使用继承
遵循这一原则的一种方法是使用继承。我们有一个对修改关闭的超类,它是基线的,并且是 jar 文件的一部分。任何想要修改超类行为的人都可以将其子类化,扩展它并添加新功能。这可确保超类行为保持不变,并且超类的客户端不必更改代码。然而,继承引入了超和子之间的紧耦合-类实现。假设超类存在缺陷或超类版本升级引入代码更改,那么子类也需要修改。
示例:假设 Jane 开了一家面包店,并决定根据她的销售额保持简单和规模。
Java
// Java Program to Illustrate Open Closed Design Principle
// Using Inheritance
// Importing input output classes
import java.io.*;
// Class 1
// Helper class acting as parent class
class Cake {
// Member variable of Cake class
private int size;
private float weight;
// Constructor for cake which sets
// only size and dimension of cake
public Cake(int size, float weight)
{
// This keyword refers to current object itself
this.size = size;
this.weight = weight;
}
// Method
// To bake the cake
public void bake()
{
// Display message only
System.out.println(
"Baking cake with base as vanilla");
// Print and display the size and weight of the cake
System.out.println("Size is " + this.size
+ " inches and weight is "
+ this.weight + " kg.");
}
}
// Class 2
// Helper class(Child class) of class 1
class PineappleCake extends Cake {
// Member variables
private int size;
private float weight;
// Constructor
// To set the dimension of the pineapple cake
public PineappleCake(int size, float weight)
{
// Super keyword refers to parent class instance
super(size, weight);
// This keyword refer to current instance
this.size = size;
this.weight = weight;
}
// Method 1
// To decorate the pineapple cake
private void decorateCake()
{
// Display messages only
System.out.println("Decorating cake");
System.out.println("Adding pineapple pieces");
}
// Method 2
// To add cream to pineapple cake
private void addCream()
{
// Print statement
System.out.println("Adding white cream");
}
// Method 3
// To bake a pineapple cake
public void bake()
{
super.bake();
// Calling the above two methods created
addCream();
decorateCake();
// Print the dimension of the pineapple cake
System.out.println("Pineapple cake - " + this.size
+ " inches is ready");
}
}
// Class 3
// Helper class(Child class) of class 1
class ChocolateCake extends Cake {
// member variables
private int size;
private float weight;
// Constructor
// Setting the size nd weight of the chocolate cake
public ChocolateCake(int size, float weight)
{
super(size, weight);
this.size = size;
this.weight = weight;
}
// Method 1
// To decorate a chocolate cake
private void decorateCake()
{
// Display commands only
System.out.println("Decorating cake");
System.out.println("Adding chocolate chips");
}
// Method 2
// To add cream to chocolate cake
private void addCream()
{
// Print statement
System.out.println("Adding chocolate cream");
}
// Method 3
// to bake a chocolate cake
public void bake()
{
super.bake();
// Calling the above two methods created
addCream();
decorateCake();
// Print and display the dimension of chocolate cake
System.out.println("Chocolate cake - " + this.size
+ " inches is ready");
}
}
// Class 4
// Main class
class GFG {
// Main driver method
public static void main(String[] args)
{
// Creating an instance of pineapple cake
// int the main() method
// Custom dimension are passed as in arguments
PineappleCake pineappleCake
= new PineappleCake(7, 3);
// Calling the bake() method of PineappleCake class
// to bake the cake
pineappleCake.bake();
// Similarly, creating an instance of chocolate cake
// in the main() method
ChocolateCake chocolateCake
= new ChocolateCake(5, 2);
// Calling the bake() method of ChocolateCake class
// to bake the cake
chocolateCake.bake();
}
}
Java
// Java Program to Illustrate Open Closed Design Principle
// Using Inheritance
// Alonside adding Parameter - Flavor to cakes
// Importing input output classes
import java.io.*;
// Class 1
// Helper class
// Acting as parent class
class Cake {
// Member variables
private int size;
private float weight;
// This is new declared variable to
// hold the flavour for the cake
private String flavor;
// Constructor
// To set the dimensions for the cake
public Cake(int size, float weight, String flavor)
{
this.size = size;
this.weight = weight;
// Here this keyword sets the
// current instance flavour to th cake
this.flavor = flavor;
}
// Method
// To bake the cake
public void bake()
{
// Printing the flavour of the desired cake
System.out.println("Baking cake with base as "
+ this.flavor);
// Printing the size and weight of the same cake
System.out.println("Size is " + this.size
+ " inches and weight is "
+ this.weight + " kg.");
}
}
// Class 2
// Helper class
class PineappleCake extends Cake {
// Member variables for the pineapple cake
private int size;
private float weight;
private String flavor;
// Constructor
// Updated as per requirements as sales rise flavour is
// added, so do setting the flavour
public PineappleCake(int size, float weight,
String flavor)
{
// Super keyword refers to parent class
super(size, weight, flavor);
// This keyword refers to current instance
this.size = size;
this.weight = weight;
this.flavor = flavor;
}
// Method 1
// To decorate the cake
private void decorateCake()
{
// Display commands only
System.out.println("Decorating cake");
System.out.println("Adding pineapple pieces");
}
// Method 2
// To add cream to the flavored pineapple cake
private void addCream()
{
System.out.println("Adding white cream");
}
// Method 3
// To bake a flavored pineapple cake
public void bake()
{
// Super keyword calls the Cake class bake() method
super.bake();
// Calling the above two methods
addCream();
decorateCake();
// Printing the dimensions of
// flavoured pineapple cake
System.out.println("Pineapple cake - " + this.size
+ " inches is ready");
}
}
// Similarly setting the same for
// the 'flavoured' chocolate cake
// Class 3
// Helper class (Base class of parent class)
class ChocolateCake extends Cake {
private int size;
private float weight;
private String flavor;
// Updated constructor
public ChocolateCake(int size, float weight,
String flavor)
{
super(size, weight, flavor);
this.size = size;
this.weight = weight;
this.flavor = flavor;
}
// Method 1
// To decorate the flavored chocolate cake
private void decorateCake()
{
System.out.println("Decorating cake");
System.out.println("Adding chocolate chips");
}
// Method 2
// To add cream to the flavoured chocolate cake
private void addCream()
{
System.out.println("Adding chocolate cream");
}
// Method 3
// To bake a flavoured chocolate cake
public void bake()
{
super.bake();
addCream();
decorateCake();
System.out.println("Chocolate cake - " + this.size
+ " inches is ready");
}
}
// Class 4
// Main class
class GFG {
// Main driver method
public static void main(String[] args)
{
// Creating a pineapple cake in the main() method
// Custom dimensions are passed as in arguments
PineappleCake pineappleCake
= new PineappleCake(7, 3, "vanilla");
// Calling the bake() method of the PineappleCake
// Class to bake the pinelapple cake
pineappleCake.bake();
// Similarly repeating the same with the chocolate
// cake
// Creating a chocolate cake by creating an object
// of ChocolateCake class in the main method
ChocolateCake chocolateCake
= new ChocolateCake(5, 2, "chocolate");
// Calling the bake() method of the ChocolateCake
// Class to bake the chocolate cake
chocolateCake.bake();
}
}
Java
// Java Program to Illustrate Open Closed Design Principle
// Using Interfaces and abstract methods
// Importing input output classes
import java.io.*;
// Interface
interface Cake {
// Abstract methods of this interface
public void bake();
public void addCream();
public void decorateCake();
}
// Class 1
// Helper class implementing above interface
class ChocolateCake implements Cake {
// Member variables of this class
private String base;
private int size;
private float weight;
// Constructor
// To set the dimension to chocolate cake
public ChocolateCake(String base, int size,
float weight)
{
this.base = base;
this.size = size;
this.weight = weight;
}
// @Override
// Method 1
// To add cream to chocolate cake
public void addCream()
{
System.out.println("Adding chocolate cream");
}
// @Override
// Method 3
// To bake the chocolate cake
public void bake()
{
// Printing the base of the cake
System.out.println("Baking cake with base as "
+ this.base);
// Calling the methods
addCream();
decorateCake();
// Printing the dimension of the chocolate cake
System.out.println("Chocolate cake with "
+ this.size
+ " inches and weight:"
+ this.weight + " kg is ready");
}
// @Override
// Method 2
// To decorate the chocolate cake
public void decorateCake()
{
// Print statement only
System.out.println(
"Cake decoration with choco chips");
}
}
// Repeating the same for pineapple cake
// as we did above for chocolate cake
// Class 2
// Helper class implementing the 'Cake' interface
class PineappleCake implements Cake {
// Member variable
private String base;
private int size;
private float weight;
// Constructor
// To set the dimension to pineapple cake
public PineappleCake(String base, int size,
float weight)
{
this.base = base;
this.size = size;
this.weight = weight;
}
// @Override
// Method 1
// To add cream to pineapple cake
public void addCream()
{
System.out.println("Adding white cream");
}
// @Override
// Method 2
// To decorate the pineapple cake
public void decorateCake()
{
System.out.println(
"Cake decoration with pineapple pieces");
}
}
// @Override
// Method 3
// To bake the pineapple cake
public void bake()
{
System.out.println("Baking cake with base as "
+ this.base);
addCream();
decorateCake();
System.out.println("Pineapple cake with " + this.size
+ " inches and weight:" + this.weight
+ " kg is ready");
}
// Class 3
// Main class
class GFG {
// Main driver method
public static void main(String[] args)
{
// Making cakes using interface and abstract methods
// by creating objects here in main() method
// Custom dimensional to both cakes are passed
// as in arguments
// 1. Pineapple cake
Cake pineappleCake
= new PineappleCake("vanilla", 7, 3);
// Calling the bake() to
// bake pineapple cake
pineappleCake.bake();
// 2. Chocolate cake
Cake chocolateCake
= new ChocolateCake("chocolate", 5, 2);
// Calling the bake() to
// bake chocolate cake
chocolateCake.bake();
}
}
Baking cake with base as vanilla
Size is 7 inches and weight is 3.0 kg.
Adding white cream
Decorating cake
Adding pineapple pieces
Pineapple cake - 7 inches is ready
Baking cake with base as vanilla
Size is 5 inches and weight is 2.0 kg.
Adding chocolate cream
Decorating cake
Adding chocolate chips
Chocolate cake - 5 inches is ready
输出说明: 'Cake' 类是基类。每个蛋糕的底料都有香草味。我们有两个专业,即菠萝和巧克力口味的蛋糕。这些类使用 Cake 的 bake() 方法制作香草蛋糕,然后添加奶油并根据口味装饰蛋糕。
Note: After few days, Jane’s bakery shop sales are high. So she decides to bake cakes with different bases to offer more varieties to her customers. With these new requirements, we need to change the ‘Cake’ class constructor, so do the changes in the above code will be reflected. The code changes are as below. However, we need to modify the subclasses to accept a 3rd parameter – flavor for the code to work.
例子:
Java
// Java Program to Illustrate Open Closed Design Principle
// Using Inheritance
// Alonside adding Parameter - Flavor to cakes
// Importing input output classes
import java.io.*;
// Class 1
// Helper class
// Acting as parent class
class Cake {
// Member variables
private int size;
private float weight;
// This is new declared variable to
// hold the flavour for the cake
private String flavor;
// Constructor
// To set the dimensions for the cake
public Cake(int size, float weight, String flavor)
{
this.size = size;
this.weight = weight;
// Here this keyword sets the
// current instance flavour to th cake
this.flavor = flavor;
}
// Method
// To bake the cake
public void bake()
{
// Printing the flavour of the desired cake
System.out.println("Baking cake with base as "
+ this.flavor);
// Printing the size and weight of the same cake
System.out.println("Size is " + this.size
+ " inches and weight is "
+ this.weight + " kg.");
}
}
// Class 2
// Helper class
class PineappleCake extends Cake {
// Member variables for the pineapple cake
private int size;
private float weight;
private String flavor;
// Constructor
// Updated as per requirements as sales rise flavour is
// added, so do setting the flavour
public PineappleCake(int size, float weight,
String flavor)
{
// Super keyword refers to parent class
super(size, weight, flavor);
// This keyword refers to current instance
this.size = size;
this.weight = weight;
this.flavor = flavor;
}
// Method 1
// To decorate the cake
private void decorateCake()
{
// Display commands only
System.out.println("Decorating cake");
System.out.println("Adding pineapple pieces");
}
// Method 2
// To add cream to the flavored pineapple cake
private void addCream()
{
System.out.println("Adding white cream");
}
// Method 3
// To bake a flavored pineapple cake
public void bake()
{
// Super keyword calls the Cake class bake() method
super.bake();
// Calling the above two methods
addCream();
decorateCake();
// Printing the dimensions of
// flavoured pineapple cake
System.out.println("Pineapple cake - " + this.size
+ " inches is ready");
}
}
// Similarly setting the same for
// the 'flavoured' chocolate cake
// Class 3
// Helper class (Base class of parent class)
class ChocolateCake extends Cake {
private int size;
private float weight;
private String flavor;
// Updated constructor
public ChocolateCake(int size, float weight,
String flavor)
{
super(size, weight, flavor);
this.size = size;
this.weight = weight;
this.flavor = flavor;
}
// Method 1
// To decorate the flavored chocolate cake
private void decorateCake()
{
System.out.println("Decorating cake");
System.out.println("Adding chocolate chips");
}
// Method 2
// To add cream to the flavoured chocolate cake
private void addCream()
{
System.out.println("Adding chocolate cream");
}
// Method 3
// To bake a flavoured chocolate cake
public void bake()
{
super.bake();
addCream();
decorateCake();
System.out.println("Chocolate cake - " + this.size
+ " inches is ready");
}
}
// Class 4
// Main class
class GFG {
// Main driver method
public static void main(String[] args)
{
// Creating a pineapple cake in the main() method
// Custom dimensions are passed as in arguments
PineappleCake pineappleCake
= new PineappleCake(7, 3, "vanilla");
// Calling the bake() method of the PineappleCake
// Class to bake the pinelapple cake
pineappleCake.bake();
// Similarly repeating the same with the chocolate
// cake
// Creating a chocolate cake by creating an object
// of ChocolateCake class in the main method
ChocolateCake chocolateCake
= new ChocolateCake(5, 2, "chocolate");
// Calling the bake() method of the ChocolateCake
// Class to bake the chocolate cake
chocolateCake.bake();
}
}
Baking cake with base as vanilla
Size is 7 inches and weight is 3.0 kg.
Adding white cream
Decorating cake
Adding pineapple pieces
Pineapple cake - 7 inches is ready
Baking cake with base as chocolate
Size is 5 inches and weight is 2.0 kg.
Adding chocolate cream
Decorating cake
Adding chocolate chips
Chocolate cake - 5 inches is ready
Note: Thus there is tight coupling between the base class that is, ‘Cake’ class, and it’s subclasses. To avoid tight coupling we go with the interface approach.
方法二:使用接口和抽象方法
- 我们用一组方法定义了一个接口。
- 接口定义了一个契约,并且它是关闭的以进行修改。根据业务需求,我们可以有不同的接口实现。这确保了类之间的松散耦合。实现类彼此独立。
实现:为了更好的理解,我们重构了前面的例子。我们有一个蛋糕界面,它有不同的烘焙蛋糕步骤。 Pineapple 和 Chocolate Cake 类实现了这个接口,定义了它们自己的面包基料、奶油和装饰。
例子:
Java
// Java Program to Illustrate Open Closed Design Principle
// Using Interfaces and abstract methods
// Importing input output classes
import java.io.*;
// Interface
interface Cake {
// Abstract methods of this interface
public void bake();
public void addCream();
public void decorateCake();
}
// Class 1
// Helper class implementing above interface
class ChocolateCake implements Cake {
// Member variables of this class
private String base;
private int size;
private float weight;
// Constructor
// To set the dimension to chocolate cake
public ChocolateCake(String base, int size,
float weight)
{
this.base = base;
this.size = size;
this.weight = weight;
}
// @Override
// Method 1
// To add cream to chocolate cake
public void addCream()
{
System.out.println("Adding chocolate cream");
}
// @Override
// Method 3
// To bake the chocolate cake
public void bake()
{
// Printing the base of the cake
System.out.println("Baking cake with base as "
+ this.base);
// Calling the methods
addCream();
decorateCake();
// Printing the dimension of the chocolate cake
System.out.println("Chocolate cake with "
+ this.size
+ " inches and weight:"
+ this.weight + " kg is ready");
}
// @Override
// Method 2
// To decorate the chocolate cake
public void decorateCake()
{
// Print statement only
System.out.println(
"Cake decoration with choco chips");
}
}
// Repeating the same for pineapple cake
// as we did above for chocolate cake
// Class 2
// Helper class implementing the 'Cake' interface
class PineappleCake implements Cake {
// Member variable
private String base;
private int size;
private float weight;
// Constructor
// To set the dimension to pineapple cake
public PineappleCake(String base, int size,
float weight)
{
this.base = base;
this.size = size;
this.weight = weight;
}
// @Override
// Method 1
// To add cream to pineapple cake
public void addCream()
{
System.out.println("Adding white cream");
}
// @Override
// Method 2
// To decorate the pineapple cake
public void decorateCake()
{
System.out.println(
"Cake decoration with pineapple pieces");
}
}
// @Override
// Method 3
// To bake the pineapple cake
public void bake()
{
System.out.println("Baking cake with base as "
+ this.base);
addCream();
decorateCake();
System.out.println("Pineapple cake with " + this.size
+ " inches and weight:" + this.weight
+ " kg is ready");
}
// Class 3
// Main class
class GFG {
// Main driver method
public static void main(String[] args)
{
// Making cakes using interface and abstract methods
// by creating objects here in main() method
// Custom dimensional to both cakes are passed
// as in arguments
// 1. Pineapple cake
Cake pineappleCake
= new PineappleCake("vanilla", 7, 3);
// Calling the bake() to
// bake pineapple cake
pineappleCake.bake();
// 2. Chocolate cake
Cake chocolateCake
= new ChocolateCake("chocolate", 5, 2);
// Calling the bake() to
// bake chocolate cake
chocolateCake.bake();
}
}
Baking cake with base as vanilla
Adding white cream
Cake decoration with pineapple pieces
Pineapple cake with 7 inches and weight:3.0 kg is ready
Baking cake with base as chocolate
Adding chocolate cream
Cake decoration with choco chips
Chocolate cake with 5 inches and weight:2.0 kg is ready
输出说明:接口提供抽象层,促进松耦合。未来,简可以推出其他口味的蛋糕,有不同的底料、奶油和装饰。