ポリモーフィズム、オーバーライド、オーバーロード
-
03-07-2019 - |
質問
Java に関して、誰かが次のように尋ねると、
ポリモーフィズムとは何ですか?
するだろう 過負荷 または オーバーライド 受け入れられる答えでしょうか?
それよりももう少し意味があると思います。
実装のないメソッドを定義する抽象基本クラスがあり、そのメソッドをサブクラスで定義した場合、それは依然としてオーバーライドされますか?
私は思う 過負荷 確かに正しい答えではありません。
解決
ポリモーフィズムを表現する最も明確な方法は、抽象基本クラス(またはインターフェイス)を使用することです
public abstract class Human{
...
public abstract void goPee();
}
このクラスは抽象です。これは、 goPee()
メソッドがHumansで定義できないためです。サブクラスMaleおよびFemaleに対してのみ定義可能です。また、人間は抽象的な概念です—男性でも女性でもない人間を作成することはできません。それはどちらかでなければなりません。
したがって、抽象クラスを使用して実装を延期します。
public class Male extends Human{
...
@Override
public void goPee(){
System.out.println("Stand Up");
}
}
and
public class Female extends Human{
...
@Override
public void goPee(){
System.out.println("Sit Down");
}
}
これで、人間でいっぱいの部屋全体におしっこをするように指示できます。
public static void main(String[] args){
ArrayList<Human> group = new ArrayList<Human>();
group.add(new Male());
group.add(new Female());
// ... add more...
// tell the class to take a pee break
for (Human person : group) person.goPee();
}
これを実行すると、次の結果が得られます。
Stand Up
Sit Down
...
他のヒント
ポリモーフィズムは、クラスインスタンスが、継承ツリー内の別のクラス(ほとんどの場合は祖先クラス)のインスタンスであるかのように動作する機能です。たとえば、Javaでは、すべてのクラスがObjectを継承します。したがって、Object型の変数を作成して、任意のクラスのインスタンスを割り当てることができます。
オーバーライドは、別のクラスを継承するクラスで発生する関数の一種です。オーバーライド関数&quot; replaces&quot;基本クラスから継承された関数ですが、そのクラスのインスタンスがポリモーフィズムによって異なる型のふりをしている場合でも呼び出されるような方法でそうします。前の例を参照すると、独自のクラスを定義してtoString()関数をオーバーライドできます。この関数はObjectから継承されるため、このクラスのインスタンスをObject型変数にコピーすると、引き続き使用できます。通常、オブジェクトのふりをしている間にクラスでtoString()を呼び出すと、実際に起動するtoStringのバージョンは、オブジェクト自体で定義されたものになります。ただし、関数はオーバーライドであるため、クラスインスタンスの真の型がポリモーフィズムの背後に隠れている場合でも、クラスのtoString()の定義が使用されます。
オーバーロードは、同じ名前で異なるパラメーターを持つ複数のメソッドを定義するアクションです。オーバーライドやポリモーフィズムとは無関係です。
擬似C#/ Javaのポリモーフィズムの例:
class Animal
{
abstract string MakeNoise ();
}
class Cat : Animal {
string MakeNoise () {
return "Meow";
}
}
class Dog : Animal {
string MakeNoise () {
return "Bark";
}
}
Main () {
Animal animal = Zoo.GetAnimal ();
Console.WriteLine (animal.MakeNoise ());
}
Main関数は動物のタイプを認識せず、MakeNoise()メソッドの特定の実装の動作に依存します。
編集:ブライアンは私を打ち負かしたようだ。面白いのは、同じ例を使用したことです。ただし、上記のコードは概念を明確にするのに役立ちます。
ポリモーフィズムとは、同じオブジェクトが要件に応じて異なる操作を実行する複数の形式を意味します。
ポリモーフィズムは 2 つの方法を使用して実現できます。
- メソッドのオーバーライド
- メソッドのオーバーロード
メソッドのオーバーロード これは、同じメソッド名を使用して同じクラスに 2 つ以上のメソッドを記述することを意味しますが、渡すパラメーターは異なります。
メソッドのオーバーライド 異なるクラスでメソッド名を使用することを意味します。つまり、親クラスのメソッドが子クラスで使用されることを意味します。
Java ではポリモーフィズムを実現するために、スーパークラスの参照変数にサブクラスのオブジェクトを保持できます。
ポリモーフィズムを実現するには、すべての開発者がプロジェクト内で同じメソッド名を使用する必要があります。
ポリモーフィズムを実現するために、オーバーライドとオーバーロードの両方が使用されます。
クラスにメソッドを含めることができます 1つまたはオーバーライド より多くのサブクラス。メソッドは に応じて異なるもの クラスはオブジェクトのインスタンス化に使用されました。
abstract class Beverage {
boolean isAcceptableTemperature();
}
class Coffee extends Beverage {
boolean isAcceptableTemperature() {
return temperature > 70;
}
}
class Wine extends Beverage {
boolean isAcceptableTemperature() {
return temperature < 10;
}
}
次のようなメソッドを持つこともできます 2つ以上の引数セットでオーバーロード。メソッドは に基づいて異なるもの 渡された引数のタイプ。
class Server {
public void pour (Coffee liquid) {
new Cup().fillToTopWith(liquid);
}
public void pour (Wine liquid) {
new WineGlass().fillHalfwayWith(liquid);
}
public void pour (Lemonade liquid, boolean ice) {
Glass glass = new Glass();
if (ice) {
glass.fillToTopWith(new Ice());
}
glass.fillToTopWith(liquid);
}
}
オーバーロードは答えではないことは正しいです。
どちらもオーバーライドしていません。オーバーライドは、ポリモーフィズムを取得する手段です。ポリモーフィズムは、オブジェクトのタイプに基づいて動作を変化させる能力です。これは、ポリモーフィズムを示すオブジェクトの呼び出し元がオブジェクトの特定のタイプを認識していない場合に最もよく実証されます。
具体的にオーバーロードまたはオーバーライドと言っても、全体像はわかりません。ポリモーフィズムは、オブジェクトのタイプに基づいて動作を特殊化する単純な機能です。
同じ名前のメソッドが異なるパラメータータイプを与えて異なる動作をする可能性がある場合、オーバーロードはポリモーフィズム(パラメトリックポリモーフィズム)の形式であるという点で、ここでの回答のいくつかに同意しません。良い例は、演算子のオーバーロードです。 &quot; +&quot;を定義できます。さまざまな種類のパラメーター(文字列や整数など)を受け入れ、それらの種類に基づいて&quot; +&quot;動作が異なります。
ポリモーフィズムには継承メソッドとオーバーライドメソッドも含まれますが、これらは基本型で抽象または仮想にすることができます。継承ベースのポリモーフィズムに関して、Javaは単一クラスの継承のみをサポートし、ポリモーフィックな動作を基本型の単一チェーンの動作に制限します。 Javaは、多態的な動作のさらに別の形式である複数のインターフェイスの実装をサポートします。
ポリモーフィズムとは、単に「多くのフォーム」を意味します。
達成するために継承を必要としません...まったく継承ではないインターフェース実装は、多態的なニーズを満たします。おそらく、インターフェイスの実装は多態的なニーズに対応する「Better」です。継承よりも。
たとえば、飛べるすべてのものを記述するスーパークラスを作成しますか?私はそうは思わないはずです。フライトを説明するインターフェースを作成し、そのままにしておくのが最適です。
したがって、インターフェイスは動作を記述し、メソッド名は(プログラマにとって)動作を記述するため、メソッドのオーバーロードをより少ない形式のポリモーフィズムと見なすのはそれほど遠くありません。
古典的な例では、犬と猫は動物であり、動物にはメソッドmakeNoiseがあります。 makeNoiseを呼び出す動物の配列を繰り返し処理し、それぞれの実装を行うことを期待できます。
呼び出し元のコードは、特定の動物が何であるかを知る必要はありません。
それがポリモーフィズムと考えているものです。
ポリモーフィズムは、オブジェクトが複数の形式で表示される機能です。これには、継承と仮想関数を使用して、交換可能なオブジェクトのファミリーを構築することが含まれます。基本クラスには、仮想関数のプロトタイプが含まれます。これは、実装されていないか、アプリケーションが指示するデフォルトの実装である場合があります。
どちらでもない:
オーバーロードとは、異なるパラメーターを取る同じ関数名がある場合です。
オーバーライドとは、子クラスが親のメソッドを独自のメソッドで置き換えることです(これ自体はポリモーフィズムを構成しません)。
ポリモーフィズムは遅延バインディングです。基本クラス(親)メソッドが呼び出されますが、実行時にアプリケーションが実際のオブジェクトが何であるかを知るまで、メソッドは異なる子クラスである可能性があります。これは、基本クラスが定義されている場所であればどの子クラスでも使用できるためです。
Javaでは、コレクションライブラリでポリモーフィズムがよく見られます:
int countStuff(List stuff) {
return stuff.size();
}
リストは基本クラスです。リストのように機能する限り、リンクされたリスト、ベクター、配列、またはカスタムリストの実装をカウントしている場合、コンパイラは手がかりを持ちません。
List myStuff = new MyTotallyAwesomeList();
int result = countStuff(myStuff);
オーバーロードしている場合、次のようになります:
int countStuff(LinkedList stuff) {...}
int countStuff(ArrayList stuff) {...}
int countStuff(MyTotallyAwesomeList stuff) {...}
etc...
そして、countStuff()の正しいバージョンがコンパイラーによって選択され、パラメーターに一致します。
オーバーロードという用語は、同じ名前を持つ何かの複数のバージョン、通常は異なるパラメーターリストを持つメソッドを持つことを指します
public int DoSomething(int objectId) { ... }
public int DoSomething(string objectName) { ... }
これらの関数は同じことをするかもしれませんが、IDまたは名前で呼び出すオプションがあります。継承、抽象クラスなどとは関係ありません。
オーバーライドは通常、質問で説明したように、ポリモーフィズムを指します
オーバーロードは、同じ名前でパラメーターが異なる2つのメソッドを定義する場合です
オーバーライドは、サブクラス内の同じ名前の関数を介して基本クラスの動作を変更する場所です。
したがって、ポリモーフィズムはオーバーライドに関連していますが、実際にはオーバーロードではありません。
ただし、誰かが「オーバーライド」という簡単な答えをくれた場合、質問「多型とは」について詳細な説明をお願いします。
オーバーライドは、上位レベルメソッド(スーパーメソッド)と同じ名前とシグネチャを持つメソッドを宣言することにより、継承されたメソッドを非表示にすることに似ています。これにより、クラスに多態的な動作が追加されます。 言い換えると、呼び出されるレベルのメソッドを選択する決定は、コンパイル時ではなく実行時に行われます。 これは、インターフェースと実装の概念につながります。
多型とは何ですか
java チュートリアル
から多型の辞書定義は、生物または種が多くの異なる形態または段階を持つことができる生物学の原則を指します。この原則は、オブジェクト指向プログラミングやJava言語などの言語にも適用できます。 クラスのサブクラスは独自の動作を定義できますが、親クラスと同じ機能の一部を共有できます。
例と定義を考慮することにより、 オーバーライド が受け入れられます。
2番目のクエリについて:
実装なしでメソッドを定義する抽象基本クラスがあり、サブクラスでそのメソッドを定義した場合、それはまだ無効ですか?
これはオーバーライドと呼ばれるべきです。
さまざまな種類のオーバーライドを理解するには、この例をご覧ください。
- 基本クラスは実装を提供せず、サブクラスは完全なメソッドをオーバーライドする必要があります-(抽象)
- 基本クラスはデフォルトの実装を提供し、サブクラスは動作を変更できます
- サブクラスは、
super.methodName()
を最初のステートメントとして呼び出して、基本クラスの実装に拡張機能を追加します - 基本クラスはアルゴリズムの構造(テンプレートメソッド)を定義し、サブクラスはアルゴリズムの一部をオーバーライドします
コードスニペット:
import java.util.HashMap;
abstract class Game implements Runnable{
protected boolean runGame = true;
protected Player player1 = null;
protected Player player2 = null;
protected Player currentPlayer = null;
public Game(){
player1 = new Player("Player 1");
player2 = new Player("Player 2");
currentPlayer = player1;
initializeGame();
}
/* Type 1: Let subclass define own implementation. Base class defines abstract method to force
sub-classes to define implementation
*/
protected abstract void initializeGame();
/* Type 2: Sub-class can change the behaviour. If not, base class behaviour is applicable */
protected void logTimeBetweenMoves(Player player){
System.out.println("Base class: Move Duration: player.PlayerActTime - player.MoveShownTime");
}
/* Type 3: Base class provides implementation. Sub-class can enhance base class implementation by calling
super.methodName() in first line of the child class method and specific implementation later */
protected void logGameStatistics(){
System.out.println("Base class: logGameStatistics:");
}
/* Type 4: Template method: Structure of base class can't be changed but sub-class can some part of behaviour */
protected void runGame() throws Exception{
System.out.println("Base class: Defining the flow for Game:");
while ( runGame) {
/*
1. Set current player
2. Get Player Move
*/
validatePlayerMove(currentPlayer);
logTimeBetweenMoves(currentPlayer);
Thread.sleep(500);
setNextPlayer();
}
logGameStatistics();
}
/* sub-part of the template method, which define child class behaviour */
protected abstract void validatePlayerMove(Player p);
protected void setRunGame(boolean status){
this.runGame = status;
}
public void setCurrentPlayer(Player p){
this.currentPlayer = p;
}
public void setNextPlayer(){
if ( currentPlayer == player1) {
currentPlayer = player2;
}else{
currentPlayer = player1;
}
}
public void run(){
try{
runGame();
}catch(Exception err){
err.printStackTrace();
}
}
}
class Player{
String name;
Player(String name){
this.name = name;
}
public String getName(){
return name;
}
}
/* Concrete Game implementation */
class Chess extends Game{
public Chess(){
super();
}
public void initializeGame(){
System.out.println("Child class: Initialized Chess game");
}
protected void validatePlayerMove(Player p){
System.out.println("Child class: Validate Chess move:"+p.getName());
}
protected void logGameStatistics(){
super.logGameStatistics();
System.out.println("Child class: Add Chess specific logGameStatistics:");
}
}
class TicTacToe extends Game{
public TicTacToe(){
super();
}
public void initializeGame(){
System.out.println("Child class: Initialized TicTacToe game");
}
protected void validatePlayerMove(Player p){
System.out.println("Child class: Validate TicTacToe move:"+p.getName());
}
}
public class Polymorphism{
public static void main(String args[]){
try{
Game game = new Chess();
Thread t1 = new Thread(game);
t1.start();
Thread.sleep(1000);
game.setRunGame(false);
Thread.sleep(1000);
game = new TicTacToe();
Thread t2 = new Thread(game);
t2.start();
Thread.sleep(1000);
game.setRunGame(false);
}catch(Exception err){
err.printStackTrace();
}
}
}
出力:
Child class: Initialized Chess game
Base class: Defining the flow for Game:
Child class: Validate Chess move:Player 1
Base class: Move Duration: player.PlayerActTime - player.MoveShownTime
Child class: Validate Chess move:Player 2
Base class: Move Duration: player.PlayerActTime - player.MoveShownTime
Base class: logGameStatistics:
Child class: Add Chess specific logGameStatistics:
Child class: Initialized TicTacToe game
Base class: Defining the flow for Game:
Child class: Validate TicTacToe move:Player 1
Base class: Move Duration: player.PlayerActTime - player.MoveShownTime
Child class: Validate TicTacToe move:Player 2
Base class: Move Duration: player.PlayerActTime - player.MoveShownTime
Base class: logGameStatistics:
あなたたちはコンセプトをミックスしていると思います。 多態性は、実行時にオブジェクトが異なる動作をする能力です。これを実現するには、次の2つの要件が必要です。
- 遅延バインディング
- 継承。
オーバーロードは、使用している言語に応じてオーバーライドとは異なることを意味すると述べました。たとえば、Javaにはオーバーライドは存在せず、オーバーロードは存在します。基本クラスとは異なるシグネチャを持つオーバーロードメソッドは、サブクラスで使用できます。そうしないと、それらはオーバーライドされます(オブジェクトの外部から基本クラスメソッドを呼び出す方法がないという事実を参照してください)。
ただし、C ++ではそうではありません。 オーバーロードメソッドは、署名が同じであるかどうか(異なる量、異なるタイプ)に関係なく、オーバーライドも同様です。つまり、サブクラスオブジェクトの外部から呼び出されると、サブクラスで基本クラスのメソッドが使用できなくなります。
だから答えは、Javaについて話すときはオーバーロードです。他の言語では、c ++で発生するように異なる場合があります
ただし、この投稿ではポリモーフィズムについて詳しく説明していますが、その理由の一部を強調したいと思います。
OOP言語でポリモーフィズムが非常に重要な理由
継承/ポリモーフィズムの有無にかかわらず、テレビ用のシンプルなアプリケーションを構築してみましょう。アプリケーションの各バージョンを投稿し、小さなレトロスペクティブを行います。
あなたはテレビ会社のソフトウェアエンジニアであり、ユーザーコマンドで値を増減するために、ボリューム、明るさ、色のコントローラーのソフトウェアを作成するように求められているとします。
追加することで、これらの各機能のクラスを書くことから始めます
- set:-コントローラーの値を設定します(コントローラー固有のコードがあると仮定)
- get:-コントローラーの値を取得します(これにコントローラー固有のコードがあるとします)
- adjust:-入力を検証し、コントローラーを設定します(一般的な検証..コントローラーに依存しません)
- コントローラを使用したユーザー入力マッピング:-ユーザー入力を取得し、それに応じてコントローラーを呼び出します。
アプリケーションバージョン1
import java.util.Scanner;
class VolumeControllerV1 {
private int value;
int get() {
return value;
}
void set(int value) {
System.out.println("Old value of VolumeController \t"+this.value);
this.value = value;
System.out.println("New value of VolumeController \t"+this.value);
}
void adjust(int value) {
int temp = this.get();
if(((value > 0) && (temp >= 100)) || ((value < 0) && (temp <= 0))) {
System.out.println("Can not adjust any further");
return;
}
this.set(temp + value);
}
}
class BrightnessControllerV1 {
private int value;
int get() {
return value;
}
void set(int value) {
System.out.println("Old value of BrightnessController \t"+this.value);
this.value = value;
System.out.println("New value of BrightnessController \t"+this.value);
}
void adjust(int value) {
int temp = this.get();
if(((value > 0) && (temp >= 100)) || ((value < 0) && (temp <= 0))) {
System.out.println("Can not adjust any further");
return;
}
this.set(temp + value);
}
}
class ColourControllerV1 {
private int value;
int get() {
return value;
}
void set(int value) {
System.out.println("Old value of ColourController \t"+this.value);
this.value = value;
System.out.println("New value of ColourController \t"+this.value);
}
void adjust(int value) {
int temp = this.get();
if(((value > 0) && (temp >= 100)) || ((value < 0) && (temp <= 0))) {
System.out.println("Can not adjust any further");
return;
}
this.set(temp + value);
}
}
/*
* There can be n number of controllers
* */
public class TvApplicationV1 {
public static void main(String[] args) {
VolumeControllerV1 volumeControllerV1 = new VolumeControllerV1();
BrightnessControllerV1 brightnessControllerV1 = new BrightnessControllerV1();
ColourControllerV1 colourControllerV1 = new ColourControllerV1();
OUTER: while(true) {
Scanner sc=new Scanner(System.in);
System.out.println(" Enter your option \n Press 1 to increase volume \n Press 2 to decrease volume");
System.out.println(" Press 3 to increase brightness \n Press 4 to decrease brightness");
System.out.println(" Press 5 to increase color \n Press 6 to decrease color");
System.out.println("Press any other Button to shutdown");
int button = sc.nextInt();
switch (button) {
case 1: {
volumeControllerV1.adjust(5);
break;
}
case 2: {
volumeControllerV1.adjust(-5);
break;
}
case 3: {
brightnessControllerV1.adjust(5);
break;
}
case 4: {
brightnessControllerV1.adjust(-5);
break;
}
case 5: {
colourControllerV1.adjust(5);
break;
}
case 6: {
colourControllerV1.adjust(-5);
break;
}
default:
System.out.println("Shutting down...........");
break OUTER;
}
}
}
}
これで、作業アプリケーションの最初のバージョンをデプロイする準備ができました。これまでに行った作業を分析する時間です。
TVアプリケーションバージョン1の問題
- Adjust(int value)コードは、3つのクラスすべてで重複しています。コードの重複を最小限に抑える必要があります。 (ただし、一般的なコードを考えていなかったため、コードの重複を避けるためにスーパークラスに移動しました)
アプリケーションが期待どおりに機能する限り、あなたはそれで生きることを決めます。
場合によっては、上司が戻ってきて、既存のアプリケーションにリセット機能を追加するように求めます。リセットすると、3つの3つのコントローラーすべてがそれぞれのデフォルト値に設定されます。
新しい機能の新しいクラス(ResetFunctionV2)の作成を開始し、この新しい機能のユーザー入力マッピングコードをマッピングします。
アプリケーションバージョン2
import java.util.Scanner;
class VolumeControllerV2 {
private int defaultValue = 25;
private int value;
int getDefaultValue() {
return defaultValue;
}
int get() {
return value;
}
void set(int value) {
System.out.println("Old value of VolumeController \t"+this.value);
this.value = value;
System.out.println("New value of VolumeController \t"+this.value);
}
void adjust(int value) {
int temp = this.get();
if(((value > 0) && (temp >= 100)) || ((value < 0) && (temp <= 0))) {
System.out.println("Can not adjust any further");
return;
}
this.set(temp + value);
}
}
class BrightnessControllerV2 {
private int defaultValue = 50;
private int value;
int get() {
return value;
}
int getDefaultValue() {
return defaultValue;
}
void set(int value) {
System.out.println("Old value of BrightnessController \t"+this.value);
this.value = value;
System.out.println("New value of BrightnessController \t"+this.value);
}
void adjust(int value) {
int temp = this.get();
if(((value > 0) && (temp >= 100)) || ((value < 0) && (temp <= 0))) {
System.out.println("Can not adjust any further");
return;
}
this.set(temp + value);
}
}
class ColourControllerV2 {
private int defaultValue = 40;
private int value;
int get() {
return value;
}
int getDefaultValue() {
return defaultValue;
}
void set(int value) {
System.out.println("Old value of ColourController \t"+this.value);
this.value = value;
System.out.println("New value of ColourController \t"+this.value);
}
void adjust(int value) {
int temp = this.get();
if(((value > 0) && (temp >= 100)) || ((value < 0) && (temp <= 0))) {
System.out.println("Can not adjust any further");
return;
}
this.set(temp + value);
}
}
class ResetFunctionV2 {
private VolumeControllerV2 volumeControllerV2 ;
private BrightnessControllerV2 brightnessControllerV2;
private ColourControllerV2 colourControllerV2;
ResetFunctionV2(VolumeControllerV2 volumeControllerV2, BrightnessControllerV2 brightnessControllerV2, ColourControllerV2 colourControllerV2) {
this.volumeControllerV2 = volumeControllerV2;
this.brightnessControllerV2 = brightnessControllerV2;
this.colourControllerV2 = colourControllerV2;
}
void onReset() {
volumeControllerV2.set(volumeControllerV2.getDefaultValue());
brightnessControllerV2.set(brightnessControllerV2.getDefaultValue());
colourControllerV2.set(colourControllerV2.getDefaultValue());
}
}
/*
* so on
* There can be n number of controllers
*
* */
public class TvApplicationV2 {
public static void main(String[] args) {
VolumeControllerV2 volumeControllerV2 = new VolumeControllerV2();
BrightnessControllerV2 brightnessControllerV2 = new BrightnessControllerV2();
ColourControllerV2 colourControllerV2 = new ColourControllerV2();
ResetFunctionV2 resetFunctionV2 = new ResetFunctionV2(volumeControllerV2, brightnessControllerV2, colourControllerV2);
OUTER: while(true) {
Scanner sc=new Scanner(System.in);
System.out.println(" Enter your option \n Press 1 to increase volume \n Press 2 to decrease volume");
System.out.println(" Press 3 to increase brightness \n Press 4 to decrease brightness");
System.out.println(" Press 5 to increase color \n Press 6 to decrease color");
System.out.println(" Press 7 to reset TV \n Press any other Button to shutdown");
int button = sc.nextInt();
switch (button) {
case 1: {
volumeControllerV2.adjust(5);
break;
}
case 2: {
volumeControllerV2.adjust(-5);
break;
}
case 3: {
brightnessControllerV2.adjust(5);
break;
}
case 4: {
brightnessControllerV2.adjust(-5);
break;
}
case 5: {
colourControllerV2.adjust(5);
break;
}
case 6: {
colourControllerV2.adjust(-5);
break;
}
case 7: {
resetFunctionV2.onReset();
break;
}
default:
System.out.println("Shutting down...........");
break OUTER;
}
}
}
}
これで、リセット機能を使用してアプリケーションの準備ができました。しかし、今ではあなたはそのことに気付き始めています
TVアプリケーションバージョン2の問題
- 製品に新しいコントローラーが導入された場合、リセット機能コードを変更する必要があります。
- コントローラーの数が非常に多くなると、コントローラーの参照を保持する際に問題が発生します。
- リセット機能コードは、すべてのコントローラークラスのコードと緊密に結合されています(デフォルト値を取得および設定するため)。
- リセットフィーチャクラス(ResetFunctionV2)は、望ましくないコントローラークラスの他のメソッド(調整)にアクセスできます。
同時に、上司から、起動時に各コントローラーが会社のホストされたドライバーリポジトリーからドライバーの最新バージョンを確認する必要がある機能を追加する必要があるかもしれないと聞きますインターネット。
アプリケーションをリファクタリングしないと、追加されるこの新しい機能はリセット機能に似ており、アプリケーションの問題(V2)が増えると考えるようになりました。
JAVAのポリモーフィック機能を利用できるように継承を使用することを考え始め、新しい抽象クラス(ControllerV3)を追加します
- getおよびsetメソッドの署名を宣言します。
- 以前にすべてのコントローラー間で複製された調整メソッドの実装を含む。
- setDefaultメソッドを宣言して、ポリモーフィズムを活用してリセット機能を簡単に実装できるようにします。
これらの改善により、TVアプリケーションのバージョン3が準備できました。
アプリケーションバージョン3
import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;
abstract class ControllerV3 {
abstract void set(int value);
abstract int get();
void adjust(int value) {
int temp = this.get();
if(((value > 0) && (temp >= 100)) || ((value < 0) && (temp <= 0))) {
System.out.println("Can not adjust any further");
return;
}
this.set(temp + value);
}
abstract void setDefault();
}
class VolumeControllerV3 extends ControllerV3 {
private int defaultValue = 25;
private int value;
public void setDefault() {
set(defaultValue);
}
int get() {
return value;
}
void set(int value) {
System.out.println("Old value of VolumeController \t"+this.value);
this.value = value;
System.out.println("New value of VolumeController \t"+this.value);
}
}
class BrightnessControllerV3 extends ControllerV3 {
private int defaultValue = 50;
private int value;
public void setDefault() {
set(defaultValue);
}
int get() {
return value;
}
void set(int value) {
System.out.println("Old value of BrightnessController \t"+this.value);
this.value = value;
System.out.println("New value of BrightnessController \t"+this.value);
}
}
class ColourControllerV3 extends ControllerV3 {
private int defaultValue = 40;
private int value;
public void setDefault() {
set(defaultValue);
}
int get() {
return value;
}
void set(int value) {
System.out.println("Old value of ColourController \t"+this.value);
this.value = value;
System.out.println("New value of ColourController \t"+this.value);
}
}
class ResetFunctionV3 {
private List<ControllerV3> controllers = null;
ResetFunctionV3(List<ControllerV3> controllers) {
this.controllers = controllers;
}
void onReset() {
for (ControllerV3 controllerV3 :this.controllers) {
controllerV3.setDefault();
}
}
}
/*
* so on
* There can be n number of controllers
*
* */
public class TvApplicationV3 {
public static void main(String[] args) {
VolumeControllerV3 volumeControllerV3 = new VolumeControllerV3();
BrightnessControllerV3 brightnessControllerV3 = new BrightnessControllerV3();
ColourControllerV3 colourControllerV3 = new ColourControllerV3();
List<ControllerV3> controllerV3s = new ArrayList<>();
controllerV3s.add(volumeControllerV3);
controllerV3s.add(brightnessControllerV3);
controllerV3s.add(colourControllerV3);
ResetFunctionV3 resetFunctionV3 = new ResetFunctionV3(controllerV3s);
OUTER: while(true) {
Scanner sc=new Scanner(System.in);
System.out.println(" Enter your option \n Press 1 to increase volume \n Press 2 to decrease volume");
System.out.println(" Press 3 to increase brightness \n Press 4 to decrease brightness");
System.out.println(" Press 5 to increase color \n Press 6 to decrease color");
System.out.println(" Press 7 to reset TV \n Press any other Button to shutdown");
int button = sc.nextInt();
switch (button) {
case 1: {
volumeControllerV3.adjust(5);
break;
}
case 2: {
volumeControllerV3.adjust(-5);
break;
}
case 3: {
brightnessControllerV3.adjust(5);
break;
}
case 4: {
brightnessControllerV3.adjust(-5);
break;
}
case 5: {
colourControllerV3.adjust(5);
break;
}
case 6: {
colourControllerV3.adjust(-5);
break;
}
case 7: {
resetFunctionV3.onReset();
break;
}
default:
System.out.println("Shutting down...........");
break OUTER;
}
}
}
}
V2の問題リストにリストされている問題のほとんどは、以下を除いて対処されました
ポリモーフィズムは、意味に関する限り、より可能性が高くなります... Javaでオーバーライドする
すべては、異なる状況での同じオブジェクトの異なる動作に関するものです(プログラミングの方法では、異なる引数を呼び出すことができます)
以下の例は理解に役立つと思います... Pure Javaコードではありませんが...
public void See(Friend)
{
System.out.println("Talk");
}
しかし、引数を変更すると...動作が変更されます...
public void See(Enemy)
{
System.out.println("Run");
}
Person(ここでは&quot; Object&quot;)は同じです...
ポリモーフィズムは、オブジェクトの複数の実装であるか、オブジェクトの複数のフォームと言えます。抽象基本クラスとして Animals
クラスがあり、動物の移動方法を定義する movement()
というメソッドがあるとします。現在、実際にはさまざまな種類の動物があり、それらは2本の足を持つ動物、4本の足を持つ動物、および足のない動物などのように動きが異なります。各動物の異なる movement()
を定義するには地球では、ポリモーフィズムを適用する必要があります。ただし、クラス Dogs
Cats
Fish
などのクラスをさらに定義する必要があります。その後、ベースクラスからこれらのクラスを拡張する必要があります動物
およびそのメソッド movement()
を、あなたが持っている各動物に基づいた新しい移動機能でオーバーライドします。また、 Interfaces
を使用してそれを実現することもできます。ここのキーワードはオーバーライドされていますが、オーバーロードは異なり、ポリモーフィズムとは見なされません。オーバーロードでは、「同じ名前の」複数のメソッドを定義できます。ただし、同じオブジェクトまたはクラスで異なるパラメーターを使用します。
ポリモーフィズムは、単一のインターフェースを使用することにより、異なるオブジェクトを均一に処理する言語の能力に関連しています。そのため、オーバーライドに関連しているため、インターフェイス(または基本クラス)はポリモーフィックであり、実装者は(同じメダルの2つの面)をオーバーライドするオブジェクトです
とにかく、2つの用語の違いは、c ++などの他の言語を使用してより適切に説明されています:ベース関数が仮想の場合、c ++の多態性オブジェクトはJavaの対応物として動作しますが、メソッドが仮想ではない場合、コードジャンプは解決された静的、および実行時にチェックされない真の型。したがって、ポリモーフィズムには、アクセスに使用されるインターフェースに応じてオブジェクトが異なる動作をする機能が含まれます。擬似コードで例を作ってみましょう:
class animal {
public void makeRumor(){
print("thump");
}
}
class dog extends animal {
public void makeRumor(){
print("woff");
}
}
animal a = new dog();
dog b = new dog();
a.makeRumor() -> prints thump
b.makeRumor() -> prints woff
(makeRumorが仮想ではないと仮定)
javaは、このレベルのポリモーフィズム(オブジェクトスライシングとも呼ばれます)を本当に提供していません。
動物a = new dog(); dog b = new dog();
a.makeRumor() -> prints thump
b.makeRumor() -> prints woff
どちらの場合でも、woffのみを出力します。 aとbはクラスdogを参照しているため
import java.io.IOException;
class Super {
protected Super getClassName(Super s) throws IOException {
System.out.println(this.getClass().getSimpleName() + " - I'm parent");
return null;
}
}
class SubOne extends Super {
@Override
protected Super getClassName(Super s) {
System.out.println(this.getClass().getSimpleName() + " - I'm Perfect Overriding");
return null;
}
}
class SubTwo extends Super {
@Override
protected Super getClassName(Super s) throws NullPointerException {
System.out.println(this.getClass().getSimpleName() + " - I'm Overriding and Throwing Runtime Exception");
return null;
}
}
class SubThree extends Super {
@Override
protected SubThree getClassName(Super s) {
System.out.println(this.getClass().getSimpleName()+ " - I'm Overriding and Returning SubClass Type");
return null;
}
}
class SubFour extends Super {
@Override
protected Super getClassName(Super s) throws IOException {
System.out.println(this.getClass().getSimpleName()+ " - I'm Overriding and Throwing Narrower Exception ");
return null;
}
}
class SubFive extends Super {
@Override
public Super getClassName(Super s) {
System.out.println(this.getClass().getSimpleName()+ " - I'm Overriding and have broader Access ");
return null;
}
}
class SubSix extends Super {
public Super getClassName(Super s, String ol) {
System.out.println(this.getClass().getSimpleName()+ " - I'm Perfect Overloading ");
return null;
}
}
class SubSeven extends Super {
public Super getClassName(SubSeven s) {
System.out.println(this.getClass().getSimpleName()+ " - I'm Perfect Overloading because Method signature (Argument) changed.");
return null;
}
}
public class Test{
public static void main(String[] args) throws Exception {
System.out.println("Overriding\n");
Super s1 = new SubOne(); s1.getClassName(null);
Super s2 = new SubTwo(); s2.getClassName(null);
Super s3 = new SubThree(); s3.getClassName(null);
Super s4 = new SubFour(); s4.getClassName(null);
Super s5 = new SubFive(); s5.getClassName(null);
System.out.println("Overloading\n");
SubSix s6 = new SubSix(); s6.getClassName(null, null);
s6 = new SubSix(); s6.getClassName(null);
SubSeven s7 = new SubSeven(); s7.getClassName(s7);
s7 = new SubSeven(); s7.getClassName(new Super());
}
}