Re-recognize the first object

Source: Internet
Author: User

From http://hi.baidu.com/gezhou/item/f386e6273a90fb8f9d63d175

A good article to understand object-oriented again. To improve everyone's Object-Oriented Programming capabilities, you can often hear the word "Object-Oriented" from the developer's mouth:

Scenario 1,

A: I started to design the program using the object-oriented method today!

B: How did you do it?

A: I encapsulate the files to be saved and loaded into a class. In the future, I can call this class to perform file operations.

Scenario 2,

A: I started to learn Java, object-oriented language. You should not learn VB any more!

B: What happened to VB?

A: VB is process-oriented and out-of-date. Java is a class and fashionable!

B: There are classes in VB!

A: (speechless)

Scenario 3,

A: The object-oriented thinking is good. I really cannot leave Java!

B: What advanced technology have you used?

A: Today, I inherited a subclass from a class that manipulated the database, rewritten the method for saving it to the database, and sent the data to the remote client through socket, the caller does not know, haha!

Scenario 4,

A: I recommend that you use Java?

B: It's really good. Object-oriented is good. There are also a lot of classes available in JDK, so you don't have to look up API documentation like in VB.

A: But I have heard that there is another aspect-oriented programming, which seems to be outdated. It seems that programming is not a long term.

Are several classes object-oriented? Is inheriting the parent class to reuse the code of the parent class? Is it possible to overwrite the parent class? There are classes in VB. Is it object-oriented?

1.1

Class and Object

Classes and objects are the most basic concepts in Object-Oriented Programming. From a Language Perspective, classes are user-defined data types with certain behaviors, "object" is a data type variable such as "class. In layman's terms, "class" is the abstraction of things with the same or similar behavior, and "object" is an example of "class, it is a group of associated code and data combinations, and an entity with certain responsibilities.

The class itself can be further abstracted as a type. A type is a high-level abstraction, which is only used to describe interfaces. For example, an abstract class and an interface are a type. When an interface of a type contains an interface of another type, we can say that it is a child type of this type. A type is used to identify a specific interface. If an object accepts all the behaviors defined by an interface, we can say that this object has this type. An object has multiple types at the same time.

Features of Object-Oriented Programming

Object-Oriented Programming has three features: encapsulation, inheritance, and polymorphism. These three features describe object-oriented features from low to advanced. Only when these three features are available can a language be called an object-oriented language. VB also has classes. Its classes also support encapsulation and simple inheritance, but it does not support all inheritance semantics and polymorphism. Therefore, VB can only be called an object-based language.

Encapsulation is a feature of all abstract data types (ADTs). Many people who are new to object-oriented think encapsulation is object-oriented. The program is divided into multiple cooperative parts according to a certain logic, and the stable parts useful to the outside are exposed, and the changes will be hidden, the outside world can only send operation requests to this object through exposed parts to enjoy the services provided by the object, without having to worry about how the object runs internally. This is encapsulation. Understanding encapsulation is the first step to understand object-oriented, and 40% of programmers only have to understand object-oriented at the encapsulation level.

Inheritance is also called derivation. In an inheritance relationship, the inherited class is called a base class, And the inherited class is called a derived class or a subclass. Inheritance is the reuse of shared object similarity while keeping objects different. The class that can be inherited always contains the common characteristics of the class of transactions that it abstracts. Inheritance provides implementation reuse. As long as we inherit from a class, we have all the actions of this class. Understanding inheritance is the second step of understanding object-oriented, and 50% of programmers only have to understand object-oriented at the inheritance level. In semantics, "inheritance" indicates that "is a (is-a)" relationship. Many humans inherit the advantages of code reuse, while ignoring the semantic features of inheritance. As a result, many misuse of Inheritance occurs. We will introduce this point later.

Polymorphism is a technology that allows users to set a parent object to one or more of its sub-objects with equal sub-objects, the base class object can operate in different ways according to the features of the derived class Object assigned to it "(Charlie Calvert ). Polymorphism expands the adaptability of objects and changes the relationship between a single object inheritance. Polymorphism is the abstraction of behavior, which enables methods with the same name to have different response methods. We can call a method by name without knowing which implementation will be executed, you don't even need to know the type of the object to execute this implementation. Polymorphism is the core concept of object-oriented programming. Only by understanding polymorphism can we understand what is truly object-oriented and truly exert the maximum capability of object-oriented. Unfortunately, only a few programmers can really understand polymorphism.

Relationship between objects

There are two basic relationships between objects: inheritance and combination.

Inheritance relationship

There are two types of inheritance relationships: one is class-to-interface inheritance, which is called interface inheritance; the other is class-to-class inheritance, which is called implementation inheritance. An inheritance relationship is a "generalization/special" relationship. The base class represents general, while the derived class represents special.

Composite relationship.

A combination is the action of combining existing objects into new objects. A combination only repeats the functions of existing programs, rather than reusing them. The difference between combination and inheritance is that it represents the relationship between the whole and the part. For example, a computer consists of CPU, memory, display, and hard disk. These components enable the computer to compute, store, and display graphics, but it cannot be said that the computer is inherited by the CPU.

1.2

There are two basic relationships between objects: inheritance and combination. The continuous iterative combination of these two relationships ultimately forms a usable program. However, you need to use these two relationships properly.

A derived class is a special type of the base class, rather than a role of the Base class. In the semantics, "inheritance" indicates the relationship between "is-a" (is a). The base class of the derived class "is-a" is the most basic prerequisite for using the inheritance relationship. If Class A is the base class of Class B, Class B should be able to replace Class A in any place where class A appears. This is the "liskov substitution rule (LSP )". If Class B cannot replace Class A where class A appears, do not design class B as a derived class of Class.

For example, "apple" is a derived class of "Fruit", so "Fruit" in the sentence "fruit is the fruit of a plant" can be replaced by "apple: "Apple is the fruit of Plants", while "apple" is not a derived class of "Bananas, because "bananas are child-degraded plant fruits" cannot be replaced by "apple" with "apple is a child-degraded plant fruit ".

This example seems redundant, but in actual development, "apple" often inherits from "Bananas.

An enterprise has an information system with a basic "customer" information, which records the customer's name, address, email, and other information. Later, the system will be upgraded to add a basic "supplier", and developers will find that "Suppliers" have all the attributes of "customers, there is only one more "bank account" attribute, so we set "supplier" as a sub-class of "customer.

Fig 2.1

By the end of the year, the boss asked all customers to send New Year greetings via email, because "supplier" is a (is-a) "customer ", therefore, the system sent New Year greetings to "Suppliers" and "customers. The next day, many suppliers were moved to call the boss. "Thank you, boss. Every time our suppliers are asking your company to buy our stuff, you will not forget us at the end of the year. Thank you very much! ". The boss was very confused. After finding the developer, the developer realized the problem. So he made a judgment in the email sending program that "if it is a supplier, it will not be sent; otherwise, it will be sent ", everything is OK. At the beginning of the year, the boss asked all "customers" who had not purchased their products for a long time to call for greetings and comments. As "supplier" is a (is-a) "customer", the next day, the following message appears: "You have made a mistake. We are your supplier! ". The boss was furious and the developers realized the seriousness of the problem. Therefore, they added a judgment in all aspects of the system involving customers: "if it is a supplier, then ......", A total of more than 60 changes were made. Of course, due to negligence, there were two omissions, so another similar accident occurred later.

We can see the harm caused by incorrect use of inheritance. In fact, a better solution is to extract a common base class "external company" from "customer" and "supplier:

Fig 2.2

In this way, the inheritance relationship between "customer" and "supplier" is removed.

A derived class should not overwrite the behavior of a base class. A derived class has the responsibility to expand the base class, rather than override the base class. If the derived class needs to overwrite or replace the behavior of the base class, the inheritance relationship between the two classes should not be established.

Let's look at another case:

A developer needs to design a warehouse receiving ticket, a warehouse picking ticket, and an inventory check ticket. All three tickets have the account logging function. by reading the customer's requirements, the developers found that the three tickets had the same login logic: traverse all the item records in the document and then log on to the account one by one. So he designed the following program:

Fig 2.3

Write the accounting logic to the abstract class "inventory business documents". The three documents can be inherited from this class. After three months, the user raised a new demand: during the inventory check, if the inventory loss of a certain goods is found to be greater than 50, the account is stopped and an alarm is reported to the operator. Therefore, the developer re-wrote the "inventory Business Document" "accounting" method in the inventory ticket to implement the logic required by the customer. After another half a month, the customer not only needs to log on to the original warehouse but also to calculate the warehouse cost. Therefore, the developer wrote the "inventory Business Document" "accounting" method in the warehouse picking order to implement the logic required by the customer. By now, the logic of the "accounting" Method for "inventory business documents" is only useful for "warehouse receiving orders", because the other two documents are "made another portal.

This is the time for us to reorganize the system design. We set the "accounting" method of the "inventory Business Document" to an abstract method. The specific implementation code is determined by the specific subclass:

Fig 2.4

Note that the "accounting" method in the "inventory Business Document" here is italic, indicating in UML this method is an abstract method. It is hard to understand that every document must be recorded, but there are differences in the Accounting Behavior of each document, therefore, defining the "accounting" method of the class in the abstract class is implemented as an abstract method with a delay to the subclass.

Inheritance has the following advantages: it is very easy to implement a new class, because most of the functions of the base class can be automatically assigned to the derived class through the inheritance relationship; it is very easy to modify or extend the inheritance implementation; as long as the parent class is modified, the behavior of the derived class is modified at the same time.

Beginners of object-oriented programming will think that inheritance is really a good thing and the best way to achieve reuse. However, as the application goes deeper, it will find that inheritance has many disadvantages: inheritance destroys encapsulation. Many internal details of the base class are visible to the derived class, so this reuse is "white box reuse". If the implementation of the base class changes, the implementation of the derived class will also change. This leads to the unpredictability of subclass behavior. The implementation inherited from the base class cannot be dynamically changed at runtime, thus reducing the flexibility of the application.

Inheritance relationships have many disadvantages. If combinations are used properly, these shortcomings can be effectively avoided. Using Composite relationships will increase the system's adaptability to changes from static to dynamic, in addition, because the combination combines existing objects into new objects, the new object can call the function of existing objects. Since the internal implementation of each object in the composite relationship is hidden, we can only call the object through the interface, so we can replace the original object with another object that implements the same interface at runtime, in this way, you can flexibly implement behavior control during runtime. In addition, the use of the compositing relationship helps to maintain the singularity of the responsibilities of each class. Such a class hierarchy and the scale of the class are unlikely to grow into an uncontrollable giant. Therefore, combination rather than inheritance is preferred.

Of course, this doesn't mean that inheritance is not good. We don't have enough classes available, but using inheritance reuse to create some practical classes will not be combined more quickly, therefore, a reasonable combination of inheritance and combination in the system will make your system powerful and strong.

1.3

Interface Concept

An interface is a type that defines methods that can be implemented by other classes. An interface cannot be instantiated or implemented by itself, it can only be implemented by other classes that support this interface. An interface is only an identifier that identifies what an object can do, but is not under its control. It is more like a contract.

Any class can implement an interface, so that the instance of this class can take effect wherever this interface is needed, so that the flexibility of the system is greatly enhanced.

Interface Programming instance

The biggest trouble for porting SQL statements between different databases is that the syntaxes supported by different databases are different. For example, the first 10 rows of data in a table are different in different databases.

MSSQLServer: Select top 10 * From t_table

MySQL: Select * From t_table limit 0, 10

ORACLE: Select * From t_table where rownum <= 10

Let's first look at the simplest practice:

First, define an SQL statement translator class:

Public class test1sqltranslator

{

Private int dbtype;

Public test1sqltranslator (INT dbtype)

{

Super ();

This. dbtype = dbtype;

}

Public String translateselecttop (string tablename, int count)

{

Switch (dbtype ){

Case 0:

Return "select top" + Count + "* from" + tablename;

Case 1:

Return "select * from" + tablename + "Limit 0," + count;

Case 2:

Return "select * from" + tablename + "where rownum <=" + count;

Default:

Return NULL;

}

}

}

Then call

Public static void main (string [] ARGs)

{

String tablename = "t_table ";

Int COUNT = 10;

Int dbtype = 0;

Test1sqltranslator translator = new test1sqltranslator (dbtype );

String SQL = translator. translateselecttop (tablename, count );

System. Out. println (SQL );

}

If you want to add support for new databases, such as DB2, you must modify the test1sqltranslator class and add a case statement for DB2. This addition can only be added when editing the source code, cannot be added dynamically at runtime. Let's take a look at how interface-based programming is implemented.

First, define the interface isqltranslator, which defines all SQL translator methods. Currently, there is only one method to translate select top:

Public interface isqltranslator

{

Public String translateselecttop (string tablename, int count );

}

Next we will write different translator classes for each database. These translator classes all implement the isqltranslator interface:

Public class mssqlservertranslator implements isqltranslator

{

Public String translateselecttop (string tablename, int count)

{

Return "select top" + Count + "* from" + tablename;

}

}

Public class mysqltranslator implements isqltranslator

{

Public String translateselecttop (string tablename, int count)

{

Return "select * from" + tablename + "Limit 0," + count;

}

}

Public class oraclesqltranslator implements isqltranslator

{

Public String translateselecttop (string tablename, int count)

{

Return "select * from" + tablename + "where rownum <=" + count;

}

}

Call the following code:

Public static void main (string [] ARGs)

{

String tablename = "t_table ";

Int COUNT = 10;

Isqltranslator translator = new mssqlservertranslator ();

String SQL = translator. translateselecttop (tablename, count );

System. Out. println (SQL );

}

After running, the following output is printed:

Select top 10 from t_table

We can see that different database translation implementations are undertaken by different classes. The biggest advantage is the high scalability. For example, a database that supports Chinese Syntax may appear one day, to make a translator for it, you only need to add another class:

Public class sinoservertranslator implements isqltranslator

{

Public String translateselecttop (string tablename, int count)

{

Return "read Table" + tablename + "before" + Count + "row ";

}

}

Modify the call code:

Public static void main (string [] ARGs)

{

String tablename = "t_table ";

Int COUNT = 10;

Isqltranslator translator = new sinoservertranslator ();

String SQL = translator. translateselecttop (tablename, count );

System. Out. println (SQL );

}

After running, the console prints out:

Read the first 10 rows of t_table

Here, the translator can be instantiated at will. As long as the instantiated class implements isqltranslator, this class can also be read through the configuration file, or even transmitted by other classes. This doesn't matter, as long as the isqltranslator interface is implemented, it can work normally.

If you want to add the verification function to the SQL statement, that is, to verify whether the translation result can be executed in the database during translation, we can steal the day by day.

First create a verifytranslator class:

Public class verifytranslator implements isqltranslator

{

Private isqltranslator translator;

Private connection;

Public verifytranslator (isqltranslator translator, connection)

{

Super ();

This. Translator = translator;

This. Connection = connection;

}

Public String translateselecttop (string tablename, int count)

{

String SQL = translator. translateselecttop (tablename, count );

Preparedstatement PS = NULL;

Try

{

PS = connection. preparestatement (SQL );

Ps.exe cute ();

} Catch (sqlexception E)

{

Dbutils. Close (PS );

Return "wrong SQL ";

}

Return SQL;

}

}

This class accepts a variable that implements the isqltranslator interface and database connection as the construction parameter. The most important thing is that this class also implements the isqltranslator interface, in this way, it can "Disguise" as an SQL translator to exercise translation responsibility, but it does not actually execute translation, it forwards the translation task to the translator variable passed through the constructor:

String SQL = translator. translateselecttop (tablename, count );

Its real task is to verify the SQL statement:

PS = connection. preparestatement (SQL );

Modify the call code again:

Public static void main (string [] ARGs)

{

String tablename = "t_table ";

Int COUNT = 10;

Isqltranslator translator = new verifytranslator (

New sinoservertranslator (), getconnection ());

String SQL = translator. translateselecttop (tablename, count );

System. Out. println (SQL );

}

After running, the console prints out:

Wrong SQL

Does the following code look familiar?

Isqltranslator translator = new verifytranslator (New sinoservertranslator (), getconnection ());

This code is very similar to the stream operations we often write:

Inputstream is = new datainputstream (New fileinputstream (new file ("C:/boot. ini ")));

This is the "modifier mode" that is often mentioned in the design pattern ".

Interface Programming

From the above example, we can see that when the code is written:

String SQL = translator. translateselecttop (tablename, count );

The code writer does not care about the instance of the class where the variable translator is. It only knows that it calls the translateselecttop method supported by the interface conventions.

When an object needs to collaborate with other objects to complete a task, it needs to know the object so that the method of the object can be called to obtain the service, the dependency of such objects on another collaboration object is called Association. If an association is not for a specific class but for an interface, any class implementing this interface can meet the requirements, because the caller only cares about whether the dependent object implements a specific interface.

When the relationship between the sent request and the specific request responder is determined during running, we call it dynamic binding. Dynamic binding allows replacement of objects with the same interface during runtime to achieve polymorphism. Polymorphism makes objects independent from each other. All InterAction operations are performed through interfaces and the dependency between them can be changed at runtime.

Programming for interfaces, rather than implementing programming, is a very important principle in object-oriented development and the essence of the design pattern!

There are countless examples of Interface Programming. For example, in hibernate, set attributes must be declared as interface types such as set, map, and list, instead, it cannot be declared as hashset, hashmap, arraylist, or other specific types. This is because Hibernate is trying to implement lazyload, I developed a class that can implement the set, MAP, list and other interfaces for the lazyload function, because the types of our properties are declared as the types of these interfaces only, therefore, Hibernate can confidently return these specific implementation classes.

In the actual development process, there are some bad habits that violate the interface programming principles:

Bad habits 1

Arraylist list = new arraylist ();

For (INT I = 0; I <10; I ++)

{

List. Add (......);

}

Here, the add method of arraylist is used, and the add method is defined in the list interface. Therefore, it is not necessary to declare the list variable as the arraylist type. The modification is as follows:

List list = new arraylist ();

For (INT I = 0; I <10; I ++)

{

List. Add (......);

}

Bad habits 2

Public void foobar (hashmap map)

{

Object OBJ = map. Get ("something ");

......

}

In this method, only the get method of the map interface is called to retrieve data. Therefore, the caller is not required to pass a hashmap type variable. Modify as follows:

Public void foobar (MAP map)

{

Object OBJ = map. Get ("something ");

......

}

After this modification, the user can call the following method to prevent the map passed to the foobar method from being modified:

Map unmodmap = collections. unmodifiablemap (MAP );

OBJ. foobar (unmodmap );

Collections. unmodifiablemap is a tool class provided by JDK. It can return a package for map and the returned map cannot be modified. This is also a typical application of the modifier mode.

Imagine if we declare the interface as public void foobar (hashmap map), can the user still call it like this?

1.4 abstract class

The main function of an abstract class is to define a public interface for its derived class. The abstract class delays the implementation of some of its operations to the derived class. The derived class can also overwrite the methods of the abstract base class, this makes it easy to define new classes. Abstract classes provide a starting point for inheritance. We often define a top-level abstract class, and then define the implementation of some locations as abstract, that is, we only define the Implemented interfaces, without defining implementation details.

An abstract class should have as much code as possible, but it cannot move the methods required only for a specific subclass to an abstract class. Some implementation methods of eclipse are not very good at this point. Some interfaces of eclipse provide methods such as createemailfield to create interface objects, these methods are not used by all subclasses. It is better to extract them into a tool class. The same error exists in jcownewdialog in our case. This class provides the createokbtn and createcancebtn methods to create the OK and cancel buttons.

In the design mode, the template method mode is the best embodiment of the advantages of the abstract class. The template method mode defines the skeleton of an algorithm, and the specific implementation steps are implemented by the specific subclass class. The inputstream class in JDK is a typical representative of the template method. It implements methods such as skip, and defines methods such as read as abstract methods for subclass implementation. In the following case, the pisabstractaction class is also an application of the template method.

In actual development, interfaces and abstract classes contribute to system reuse in two directions. Interfaces define system service contracts, while abstract classes define public implementations for these services, subclass can inherit from these abstract classes, so that you do not need to implement the methods you do not care about. If the service implementation provided by the abstract class does not meet your own requirements, then you can implement the service contract of the interface from the ground up.

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.