IAnimal.cfc インターフェイスを定義します。
ColdFusion のコンポーネントについては、ColdFusion のコンポーネントの作成と使用を参照してください。
ColdFusion の OOP の新機能と強化機能について詳しくは、以下を参照してください。
抽象コンポーネントと抽象メソッド
抽象コンポーネントには、body のない抽象メソッドや、実装のあるメソッドを含めることができます。
抽象コンポーネントや抽象メソッドを作成するには、abstract キーワードを使用します。ColdFusion では、抽象コンポーネントをインスタンス化できません。抽象コンポーネントは、多くの場合、サブコンポーネントのベースを提供するために使用されます。最初の実体コンポーネントの継承階層に、すべての抽象メソッドの実装を含める必要があります。
実体コンポーネントに抽象メソッドを含めることはできません。
抽象コンポーネントを宣言するには、次のようにします。
// myAbstractClass.cfc abstract component { // abstract methods // concrete methods }
以上が、ColdFusion で抽象コンポーネントを宣言する方法です。
myAbstractClass のインスタンスを作成することはできません。そのため、次のコードは有効ではありません。
myClassInstance=new myAbstractComponent();
ColdFusion で抽象コンポーネントを使用する例を次に示します。
Shape.cfc
abstract component Shape{ abstract function draw(); }
Square.cfc
component Square extends="Shape" { function draw() { writeoutput("Inside Square::draw() method. <br/>"); } }
ShapeFactory.cfc
component ShapeFactory extends="AbstractFactory" { Shape function getShape(String shapeType){ if(shapeType EQ "RECTANGLE"){ return new Rectangle(); }else if(shapeType EQ "SQUARE"){ return new Square(); }else return "not defined"; } }
Rectangle.cfc
component Rectangle extends="Shape" { function draw() { writeoutput("Inside Rectangle::draw() method. <br/>"); } }
AbstractFactory.cfc
abstract component AbstractFactory { abstract Shape function getShape(String shape) ; }
FactoryProducer.cfc
component FactoryProducer { AbstractFactory function getFactory(String choice){ if(choice eq "SHAPE"){ return new ShapeFactory(); } } }
index.cfm
<cfscript> //get shape factory shapeFactory = new FactoryProducer().getFactory("SHAPE"); //get an object of Shape Rectangle shape2 = new shapeFactory().getShape("RECTANGLE"); //call draw method of Shape Rectangle shape2.draw(); //get an object of Shape Square shape3 = new shapeFactory().getShape("SQUARE"); //call draw method of Shape Square shape3.draw(); </cfscript>
final コンポーネント、final メソッド、final 変数
ColdFusion では、継承は非常に有用な機能です。しかし、データのセキュリティ違反を防ぐために、コンポーネントを他のクラスで拡張してはいけない場合があります。そうした場合のために、final キーワードがあります。
ColdFusion では次がサポートされています。
- final コンポーネント
- final メソッド
- final 変数
final 変数
final 変数 は 定数です。変数を宣言する際に final キーワードを使用します。final 変数は初期化後に値を変更することができません。次に例を示します。
component{ final max=100; function mymethod(){ //max=100; writeoutput("final variable is: " & max); } }
index.cfm を作成し、コンポーネントをインスタンス化して、そのコンポーネントに定義されているメソッドを呼び出します。そのメソッドで max の値を変更すると、例外が発生します。次のスニペットでも例外が生成されます。
component{ final max; // constructor function mymethod(){ max=50; writeoutput("final variable is: " & max); } }
final コンポーネント
final コンポーネントを拡張し、final メソッドをオーバーライドすることはできません。ただし、final コンポーネントで他のコンポーネントを拡張することはできます。
final コンポーネントを宣言するには、以下の例を参照してください。
final component{ // define methods }
final メソッドを定義するには、final キーワードと戻り型の前に指定子を使用します。次に例を示します。
public final void function myMethod() { // method body }
final コンポーネントはデータのセキュリティを確保するのに役立ちます。ハッカーはよくコンポーネントのサブコンポーネントを作成し、それを元のコンポーネントと置き換えます。そのサブコンポーネントは元のコンポーネントに似ていますが、悪意のある操作を実行し、アプリケーション全体が危険にさらされる可能性があります。そうした行為を防ぐには、コンポーネントを final として宣言し、サブコンポーネントを作成できないようにします。次に例を示します。
A.cfc
final component { }
以下のコードでは例外が生成されます。
B.cfc
component extends=”A” { }
final メソッド
final キーワードを使用したメソッドはオーバーライドできません。そのため、サブコンポーネントから変更できない機能を作成できます。次に例を示します。
Test.cfc
component { // final method and cannot be overridden public final void function display(){ writeOutput("From super class, final display() method"); } // concrete method public void function show(){ writeOutput("From super class, non-final show() method"); } }
Demo.cfc
component extends="Test"{ //public void function display(){} public void function show() { writeOutput("From subclass show() method"); } }
Demo. cfc では、上記の行のコメントを解除すると 例外が生成されます。 final メソッドはオーバーライドできないからです。ただし、上記のコードに示すように、final 以外のメソッドはオーバーライドできます。
main.cfm
<cfscript> d1=new Demo(); d1.display(); d1.show(); </cfscript>
出力
From super class , final display() method
From subclass show() method
インターフェイスのデフォルトの関数
この機能を使用すると、シグネチャではなく、インターフェイスの関数を宣言できます。開発者は、インターフェイスを拡張する際に、デフォルトの実装をオーバーライドするか、再利用するかを選択できます。
デフォルトの関数を使用すると、古いアプリケーションとの互換性を保ったままインターフェイスを拡張できます。
例えば、any 型のオブジェクトを返す returnsany 関数を定義する I.cfc インターフェイスを作成します。そうした関数を定義する際に、「default」キーワードを使用します。
interface { public default any function returnsany(any obj) { return obj; } }
I.cfc インターフェイスを実装する comp.cfc を作成します。
component implements="I" { }
次に、文字列を返すオブジェクトを作成します。
<cfscript> myobj=new Comp(); writeOutput(myobj.returnsany("hello world")); </cfscript>
共変性
共変性とは、型とサブ型の間の関係です。ColdFusion(2021 リリース)では、メソッドをオーバーライドする際の戻り型で共変性がサポートされています。
ColdFusion(2021 リリース)では、インターフェイスを実装するコンポーネントの戻り型は共変です。以下の例は、共変性を利用する方法を示しています。
インターフェイスの実装時に引数名は比較されません。つまり、インターフェイスの関数が引数名を x として受け取っても、コンポーネントに実装されている関数では任意の引数名を使用できます。
-
interface displayName="IAnimal" hint="Animal Interface."{ any function eat(any prey=""); any function makeNoise(string noise); }
-
インターフェイスを実装するコンポーネント Animal.cfc を定義します。
インターフェイス関数 eat() および makenoise () の実装時に、戻り値の型がより具体的な型にオーバーライドされます。これはメソッドの共変戻り値型と呼ばれます。
component implements="IAnimal" displayname="Animal"{ property animalSize; property animalType; function init(animalSize,animalType){ variables.instance.animalSize = arguments.animalSize variables.instance.animalType = arguments.animalType } Animal function eat(any prey=""){ return prey; } string function makeNoise(string noise){ return noise; } function getanimalSize(){ return variables.instance.animalSize } function getanimalType(){ return variables.instance.animalType } }
-
index.cfm を作成し、これらの関数の動作を確認します。
<cfscript> bunny=new Animal('small','rabbit'); simba =new Animal('large','Tiger'); writeoutput("Simba eats " & simba.eat(bunny).getAnimaltype() & "<br/>"); writeoutput("Simba " & simba.makenoise('roarsss')); </cfscript>