Object-oriented languages enable you to declare classes whose names and interfaces closely mimic real-world problem domain entities such that using theobjects have a more natural "feel" to them. The result of removing the elements not directly related to solving the problem at hand is that you're able to focus specifically on the problem and greater productivity.
However, that's one level of abstraction. If you take that a step further, as a class developer you need to think in terms of how you can best design abstractions for your class's clients to allow the client to focus on the task at hand and not be mired in the details of how your class works. At this point, a good question might be, "How does a class's interface relate to abstraction?" The class's interface is the implementation of the abstraction.
I'll use a somewhat familiar analogy from programming courses to help crystallize these concepts: the internal workings of vending machines. The internals of a vending machine are actually quite involved. To fulfill its responsibilities, the machine has to accept cash and coinage, make change, and dispense the selected item. However, the vending machine has a finite set of functions it needs to express to its users. This interface is expressed through a coin slot, buttons for selecting the desired item, a lever to request change, a slot that holds the returned change, and a shoot to dispense the selected item. Each of these items represents a part of the machine's interface. Vending machines have, by and large, remained much the same since their invention. This is because despite the fact that the internals have changed as technology has evolved, the basic interface has not needed to change much. An integral part of designing a class's interface is having a deep enough understanding of the problem domain. This understanding will help you create an interface that gives the user access to the information and methods that they need yet insulates them from the internal workings of the class. You need to design an interface not only to solve today's problems but also to abstract sufficiently from the class's internals so that private class members can undergo unlimited changes without affecting existing code.
Another equally important aspect of designing a class's abstraction is keeping the client programmer in mind at all times. Imagine that you're writing a generic database engine. If you're a database guru, you might be perfectly comfortable with terms like cursors, commitment control, and tuples. However, most developers who haven't done a lot of database programming aren't going to be as knowledgeable about these terms. By using terms that are foreign to your class's clients, you have defeated the entire purpose of abstraction-to increase programmer productivity by representing the problem domain in natural terms.-
Another example of when to think about the client would be when determining which class members should be publicly accessible. Once again, a little knowledge of the problem domain and your class's clients should make this obvious. In our database engine example, you'd probably not want your clients to be able to directly access members representing internal data buffers. How these data buffers are defined could easily change in the future. In addition, because these buffers are critical to the overall operation of your engine, you'd want to make sure that they are modified through your methods only. That way you can be assured that any necessary precautions are taken.
You might think that object-oriented systems are designed primarily to make it easier to create classes. Although this feature does provide for short-term productivity gains, long-term gains come only after realizing that OOP exists to make programming easier for the class's clients. Always consider the programmer who is going to instantiate or derive from the classes that you create when designing your classes.