CS 535 Object-Oriented Programming Fall Semester, 2003 Abstract Classes, Inheritance & Testing |
||
---|---|---|
© 2003, All Rights Reserved, SDSU & Roger Whitney San Diego State University -- This page last updated 21-Oct-03 |
Abstract Classes
Abstract class – a class not used to create instances of itself
Concrete class – a class that we do create direct instances of
Why Abstract Classes
Defining an Abstract Class
Some languages have special syntax for abstract classes
public abstract class NoObjects { public void aFunction() { System.out.println( "Hi Mom" ); } public abstract void subClassMustImplement( int foo ); }
Smalltalk does not have special syntax for abstract classes
Collection>>do: aBlock self subclassResponsibility
What does self subclassResponsibility do?
Inform reader
How to Prohibit Instances of Abstract Class
Documentation is normally enough
Implement new so it throws an exception
Stream class>>new "Provide an error notification that Streams are not created using this message." self error: ('Streams are created with on: and with:')
How do subclass objects get created?
PositionableStream is a subclass of Stream
PositionableStream class>>on: aCollection ^super new on: aCollection “Throws and Exception”Use basicNew
PositionableStream class>>on: aCollection ^self basicNew on: aCollection
basicNew
Some Collection Classes
(N) indicates number of methods defined the class
Bold indicates concrete classes
Abstract Classes and Data
Abstract classes commonly do not have instance variables
How can they implement methods?
Identify a core set of abstract operations
Implement other methods using core methods
Collection Class
Collection does not have any instance variables
Collection implements
Collection>>detect: aBlock ifNone: exceptionBlock self do: [:each | (aBlock value: each) ifTrue: [^each]]. ^exceptionBlock value
Collection>>do: aBlock self subclassResponsibility
Abstract Classes, Types and Hinges
Tagging (declaring) a variable to be an Abstract class instance
SomeClass>>foo: aCollection ^aCollection fold: [:a :b | a max: b].
public class SomeClass { public int foo(Collection a) { blah} }
public class Resticted { public int foo(Array a) { blah} }
Abstract Classes and Hiding
Smalltalk VM on startup informs Filename of the correct concrete class for the current platform
‘foo’ asFilename Filename named: ‘foo’
Create an instance of the correct concrete Filename class
Platform Independence Aside
End of line Characters
Mac, PC and Unix have different end of line characters
When you read a file:
Abstract Classes and Hiding
String is an abstract class
String new
Strings Continued
| a | a :=String new. a class. "returns ByteString"
| b | b :=(String with: (Character value: 3585)) "3585 is Thai character". b class "returns TwoByteString"
| c | c := String with: $a. c class. “returns ByteString” c at: 1 put: (Character value: 3585). c class “returns TwoByteString”
To learn about character encodings read:
http://www.joelonsoftware.com/articles/Unicode.html
become: Smalltalk Magic
| c | c := String with: $a. c class. “returns ByteString” c at: 1 put: (Character value: 3585). c class “returns TwoByteString”
How did c change class?
a become: b
String Transformation without become?
Use composition
String has instance variable that holds real string
String forwards messages to the real string
String can replace the real string with a different object
Smalltalk.Core defineClass: #String superclass: #{Core.CharacterArray} indexedType: #none private: false instanceVariableNames: 'realString' classInstanceVariableNames: '' imports: '' category: 'Collections-Text'
size ^realString size
at: anInteger ^realString at: anInteger
at: anInteger put: aCharacter aCharacter value > 256 ifTrue: [realString := realString atTwoByteString]. realString at: anInteger put: aCharacter.
Inheritance
What should I use as a super class?
Common Mistakes
Engine Subclass of Car
Using a has-a relation for inheritance
Car subclass of Engine
“I need access to engine methods in the car class and now I have it.”
Roles Verses Classes
2.11 Be sure the abstractions you model are classes and not simply the roles objects play
BinarySearchTree>>initialize
left := LeftNode new.
right := RightNode new.
BinarySearchTree>>initialize
left := Node new.
right := Node new.
initialize mother := Mother new. father := Father new. etc. initialize mother := Person new. father := Person new. etc.
What to Test
Everything that could possibly break
How often do accessor methods have errors?
Node>>value ^value
How many errors did your WordStream>>next method have?
Some Guidelines
Test values
Common Things that Programs Handle Incorrectly
Adapted with permission from “A Short Catalog of Test Ideas” by Brian Marick, http://www.testing.com/writings.html
Strings
Test using empty String
Collections
Test using:
Do we need to test all methods?
Character>>isWordSeparator ^self isSeparator | (#($, $. $; $' $" $? $!) includes: self)
Character>>dollarValue self isAlphabetic ifFalse:[^0]. ^self asLowercase asInteger - $a asInteger + 1
String>>dollarValue ^self inject: 0 into: [:subTotal :next | subTotal + next dollarValue]
String>>words ^self runsFailing: [:each | each isWordSeparator]
String>>dollarWords ^self words select: [:each | each dollarValue = 100]Can we just test String>>dollarWords?
If String>>dollarWords works correctly then all the other methods are highly likely to also work correctly
Benefit
Can we just test
String>>dollarValue String>>words
If these methods work what could be wrong with String>>dollarWords?
Copyright ©, All rights reserved.
2003 SDSU & Roger Whitney, 5500 Campanile Drive, San Diego, CA 92182-7700 USA.
OpenContent license defines the copyright on this document.
Previous    visitors since 21-Oct-03    Next