Introduction to Interfaces
Introduction to Interfaces
An Object's Interface
Introduction
An interface is a list of items that can be used to create a class. The interface itself is not a class; it only provides a list of actions that a class would need.
Like a class or a structure, an interface has members but those members are not defined. Each member simply indicates its name but also provides such information as its type(s) of argument(s), if any, and its return type.
To create an interface, type type followed by a name. By tradition, the name of an interface starts with I (i in uppercase). After the name of the interface, type the = symbol.
The Body of an Interface
The section after the = symbol is the body of the interface. In that body, you can create the desired behavior of the interface.
An Empty Interface
The body of an interface can start with the interface keyword. In that case, you must end the body with the end keyword. Here is an example:
type ICircular = interface end
Notice that there is no member in the body of this interface. Such an interface is referred to as empty. You can create such an interface to test something without the need to formally create an interface.
Populating an Interface
An interface can contain just one member. In that case, you can create that member just after the = symbol that introduces the body of the interface. Here is an example:
type ICircular = ...
As mentioned already, you can delimit the body of the interface with interface and end. Here is an example:
type ICircular = interface ... end
In most cases (not all cases), an interface contains more than one member. In such a situation, the body of the interface must start on the next line. Here is an example:
type ICircular =
...
As a result, the common formula to create an interface is:
type interface-name = [ interface ] abstract member-1 : [ data-type 1 -> ] return-type-1 abstract member-2 : [ data-type 2 -> ] return-type-2 abstract member_n : [ data-type_n -> ] return-type_n [ end ]
Again, you can delimit the body of the interface with interface and end. Here is an example:
type ICircular = interface ... end
Introduction to the Members of an Interface
An Abstract Member in an Interface
In the body of the interface, you can create the members you want. To start, you can create each member as an abstraction. In this case, start the member with the abstract keyword. Add a name for the members. If you are creating a property, add a colon and a data type. Here is an example:
type ICircular = interface abstract Area : float end
Implementing an Interface
Once an interface exists, any class that needs its functionality must imprement it. The formula to follow to implement an interface is:
type class-name[(parameter(s))] = member(s) interface interface-name with interface-member(s)
To implement an interface, in the body of the class, after the local members of the class, type interface, followed by the name of the interface, and followed by with. After this and on the next line, implement the member(s) of the interface. Here is an example:
type ICircular = interface abstract member Circumference : unit -> double abstract Area : unit -> double end type Circle(radius : double) = member this.Radius : double = radius; interface ICircular with member this.Circumference() = radius * 2.00 * 3.14156 member this.Area() : double = radius * radius * 3.14156
Using an Interface
Introduction
To use the functionaity of an interface, you must cast an object created from a class implementer to its interface. There are various techniques you can use.
Up-Casting an Object
After implementing an interface in a class, you can create an object of the class by declaring a variable from that class. To access a method from the interface, declare another variable in that same class but you must up-cast it to the interface. Here is an example:
type ICircular =
abstract Circumference : unit -> double
abstract Area : unit -> double
type Circle(radius : double) =
member this.Radius : double = radius;
interface ICircular with
member this.Circumference() = radius * 2.00 * 3.14156;
member this.Area() : double = radius * radius * 3.14156;
let circ = new Circle(28.14);
let disc = circ :> ICircular;
printfn "Circle Characteristics";
printfn "----------------------";
printfn "Radius: %f" circ.Radius;
printfn "Circumference: %f" (disc.Circumference());
printfn "Area: %f" (disc.Area());
Localling Casting an Object
Instead of first declaring a variable, you can also use a local cast. Here are examples:
type ICircular = abstract Circumference : unit -> double abstract Area : unit -> double type Circle(radius : double) = member this.Radius : double = radius; interface ICircular with member this.Circumference() = radius * 2.00 * 3.14156; member this.Area() : double = radius * radius * 3.14156; let circ = new Circle(28.14); let around = (circ :> ICircular).Circumference(); printfn "Circle Characteristics"; printfn "-------------------------"; printfn "Radius: %f" circ.Radius; printfn "Circumference: %f" around; printfn "Area: %f\n" ((circ :> ICircular).Area());
This would produce:
Circle Characteristics ------------------------- Radius: 28.140000 Circumference: 176.806997 Area: 2487.674445 Press any key to continue . . .
Up-Casting a Method
As another technique, when implementing an interface in a class, after defining a method of the interface, create another member function that holds the same name as the method. To define that other method, create an upcast and call the method of the interface. The formula to follow is:
member | self-identifier | interface-name].interface-method() = ([self-identifier | interface-name] :> interface-name).interface-method()
Start with the member keyword. It is followed by either a self-identifier (this, self, a letter or word of your choice, or else) or the name of the interface. This is followed by a period and the name of the method from the interface with its parentheses and the = sign. Add some parentheses. In the parentheses, use the same option you chose for the Self identifier or the name of the interface. The same Self identifier must be used on both sides. If you decide to use the name of the interface, you must use it on both sides. After the up-cast, access the name of the method using a period and end it with parentheses. Once this has been done, you can access the interface method from an object created from the class. Here are examples:
type ICircular =
abstract Circumference : unit -> double
abstract Area : unit -> double
type Circle(radius : double) =
member this.Radius : double = radius
member me.Circumference() = (me :> ICircular).Circumference()
member ICircular.Area() = (ICircular :> ICircular).Area()
interface ICircular with
member this.Circumference() = radius * 2.00 * 3.14156
member this.Area() : double = radius * radius * 3.14156
let circ = new Circle(46.8506);
printfn "Circle Characteristics";
printfn "-------------------------";
printfn "Radius: %f" circ.Radius;
printfn "Circumference: %f" (circ.Circumference());
printfn "Area: %f\n" (circ.Area());
This would produce:
Circle Characteristics ------------------------- Radius: 46.850600 Circumference: 294.367942 Area: 6895.657349 Press any key to continue . . .
Implementing Many Interfaces
F# doesn't support multiple inheritance, which is the ability to create a class that is directly based on many classes. As an alternative, you can create a class that implements more than one interface.
The formula to implement many interfaces is:
type class-name[(parameter(s))] = member(s) interface interface-name 1 with interface-member(s) 1 interface interface-name 2 with interface-member(s) 2 . . . interface interface-name n with interface-member(s) n
In the body of the class, each interface has its implementation section. The individual implementations follow the techniques we have used so far. To access the member of an interface from the object created using the class, you can declare a variable that is up-cast from the interface. This can be done as follows:
type ICircular = abstract Circumference : unit -> double abstract Area : unit -> double type IQuadrilateralArea = abstract Area : double * double -> double type Circle(radius : double) = member this.Radius : double = radius; member me.Circumference() = (me :> ICircular).Circumference(); member ICircular.Area() = (ICircular :> ICircular).Area(); interface ICircular with member this.Circumference() = radius * 2.00 * 3.14156; member this.Area() : double = radius * radius * 3.14156; type Cylinder(radius : double, height : double) = member this.Radius : double = radius member this.Height : double = height member me.Circumference() = (me :> ICircular).Circumference() member ICircular.BottomArea() = (ICircular :> ICircular).Area() interface ICircular with member this.Circumference() = radius * 2.00 * 3.14156 member this.Area() : double = radius * radius * 3.14156 interface IQuadrilateralArea with member this.Area(length : double, width : double) : double = length * width let cup = new Cylinder(35.74, 22.82); let around = cup :> ICircular; let lateral = cup :> IQuadrilateralArea; printfn "Ice Cream Cup Characteristics"; printfn "-------------------------"; printfn "Radius: %0.2f" cup.Radius; printfn "Circumference: %0.2f" (around.Circumference()); printfn "Bottom Area: %0.2f" (cup.BottomArea()); printfn "Lateral Area: %0.2f\n" (lateral.Area(around.Circumference(), cup.Height));
This would produce:
Ice Cream Cup Characteristics ------------------------- Radius: 35.74 Circumference: 224.56 Bottom Area: 4012.86 Lateral Area: 5124.43 Press any key to continue . . .
Properties in an Interface
A property is called abstract if it is not defined. Any class that wants to use that property must implement it.
|
|||
Previous | Copyright © 2014-2024, FunctionX | Monday 14 February 2022 | Next |
|