{"id":53,"date":"2017-09-09T15:33:34","date_gmt":"2017-09-09T15:33:34","guid":{"rendered":"https:\/\/wp-systeme.lip6.fr\/potop-butucaru\/?p=53"},"modified":"2023-04-03T16:11:40","modified_gmt":"2023-04-03T16:11:40","slug":"interfaces-et-classes-abstraites","status":"publish","type":"post","link":"https:\/\/wp-systeme.lip6.fr\/potop-butucaru\/2017\/09\/09\/interfaces-et-classes-abstraites\/","title":{"rendered":"Interfaces et Classes Abstraites"},"content":{"rendered":"<section>\n<section class=\"toc-pause\">\n<h1>Interfaces<\/h1>\n<\/section>\n<section>\n<h2>H\u00e9ritage et Sous-Type<\/h2>\n<p>On a vu l&#8217;int\u00e9r\u00eat de l&#8217;h\u00e9ritage et du polymorphisme pour le sous-typage.<\/p>\n<pre><code class=\"java\" data-trim=\"\">\r\nAnimal a1 = Math.random() &lt; 0.5 ? new Dog() : new Cat();\r\na1.speak();\r\n                      <\/code><\/pre>\n<p class=\"fragment\">Ce qui permet l&#8217;utilisation de variables de type g\u00e9n\u00e9rique, pouvant stocker des objets qu&#8217;on utilise quelque soit leur type.<\/p>\n<p class=\"fragment\">Ceci est rendu possible par la red\u00e9finition des m\u00e9thodes et le polymorphisme.<\/p>\n<\/section>\n<section>\n<h2>H\u00e9ritage et Sous-Type<\/h2>\n<p>C&#8217;est parfois l&#8217;utilit\u00e9 principale de l&#8217;h\u00e9ritage, plus que la &#8220;r\u00e9utilisation du code de la classe de base&#8221;.<\/p>\n<\/section>\n<section>\n<h2>H\u00e9ritage et Sous-Type<\/h2>\n<p>C&#8217;est tellement utile qu&#8217;on aimerais parfois qu&#8217;un objet h\u00e9rite de plusieurs classe, afin de lui associ\u00e9 plusieurs types.<\/p>\n<p class=\"fragment\">Impossible car on ne peut h\u00e9riter que d&#8217;une classe.<\/p>\n<\/section>\n<section>\n<h2>Interfaces<\/h2>\n<p>Les interfaces permettent de cr\u00e9er des sous-types mais sans cr\u00e9er de classe de base.<\/p>\n<p class=\"fragment\">On \u00e0 la m\u00eame relation &#8220;EST UN&#8221; entre un objet et une interface.<\/p>\n<p class=\"fragment\">Par exemple on pourrait dire &#8220;Un objet est Inflammable s&#8217;il propose une m\u00e9thode enflammer()&#8221;<\/p>\n<p class=\"fragment\">Les objets inflammables n&#8217;ont pas vraiment de choses en commun que l&#8217;on pourrait centraliser dans une classe <code>Inflammable<\/code>. Il n&#8217;h\u00e9rite pas de propri\u00e9t\u00e9 avec cette relation (\u00e0 part l&#8217;existence de cette fonction).<\/p>\n<\/section>\n<section>\n<h2>Interfaces<\/h2>\n<p>Une <b>interface<\/b> est une liste de noms de m\u00e9thodes (uniquement les signatures des m\u00e9thodes).<\/p>\n<p class=\"fragment\">Une interface est un prototype de classe. Elle d\u00e9finit la signature des m\u00e9thodes qui doivent \u00eatre impl\u00e9ment\u00e9es dans les classes construites a\u0300 partir de ce prototype.<\/p>\n<\/section>\n<section>\n<h2>Interfaces<\/h2>\n<p>On dit qu&#8217;une classe <b>impl\u00e9mente<\/b> une interface, si elle <b>d\u00e9finit les m\u00e9thodes de l&#8217;interface<\/b>.<\/p>\n<p class=\"fragment\">En java on d\u00e9clare qu&#8217;une classe impl\u00e9mente une interface avec le mot cl\u00e9 <code>implements<\/code>.<\/p>\n<p class=\"fragment\">Une interface d\u00e9finit un type (comme une classe) et les classes qui impl\u00e9mentent cette interface sont donc des sous-types.<\/p>\n<\/section>\n<section>\n<h2>Exemple<\/h2>\n<pre><code class=\"java\" data-trim=\"\">\r\ninterface Inflammable {\r\n    void enflammer();\r\n}\r\n\r\nclass Bois implements Inflammable {\r\n\tpublic void enflammer() {\r\n\t\tSystem.out.println(\"Je brule et fais des braises\");\r\n\t}\r\n}\r\n\r\nclass Dancefloor  implements Inflammable {\r\n\tpublic void enflammer() {\r\n\t\tSystem.out.println(\"\u266a \u266b Youhouhou \u266c \u266b \");\r\n\t}\r\n}\r\n\r\npublic class Main {\r\n    static public void main(String[] args) {\r\n        Inflammable[] tab = { new Bois(), new Dancefloor() };\r\n\r\n        for(Inflammable i : tab)\r\n        \ti.enflammer();\r\n    }\r\n}\r\n    <\/code><\/pre>\n<p>Le mot cl\u00e9 <code>public<\/code> est implicite dans une interface.<\/p>\n<p><a href=\"https:\/\/repl.it\/DRDg\/1\" target=\"_blank\" rel=\"noopener\">Run it!<\/a><\/section>\n<section>\n<h2>Interfaces<\/h2>\n<p>Avantage :<\/p>\n<ul>\n<li class=\"fragment\">Une classe peut impl\u00e9menter plusieurs interfaces.<\/li>\n<li class=\"fragment\">On a tous les avantages du sous-typage comme avec l&#8217;h\u00e9ritage classique (notamment le polymorphisme).<\/li>\n<\/ul>\n<p>&nbsp;<\/p>\n<\/section>\n<section>\n<h2>Exemple 2<\/h2>\n<pre><code class=\"java\" data-trim=\"\">\r\npublic interface Comparable {\r\n    boolean greaterThan(Object o);\r\n}\r\nclass Maximize {\r\n    static public Comparable max(Comparable a, Comparable b) {\r\n        if(a.greaterThan(b)) {\r\n            return a;\r\n        }\r\n        return b;\r\n    }\r\n}\r\n\r\nclass Person implements Comparable {\r\n    private int size;\r\n    Person(int size) { this.size = size; }\r\n    @Override\r\n    public String toString() { return \"size: \"+size; }\r\n    public boolean greaterThan(Object o) {\r\n        return this.size &gt; ((Person)o).size;\r\n    }\r\n}\r\npublic class Main {\r\n    static public void main(String[] args) {\r\n        Person p1 = new Person(157);\r\n        Person p2 = new Person(173);\r\n        System.out.println(Maximize.max(p1, p2));\r\n    }\r\n}\r\n<\/code><\/pre>\n<p><a href=\"https:\/\/repl.it\/DRGj\" target=\"_blank\" rel=\"noopener\">run it!<\/a><\/section>\n<section>\n<h2>Interface<\/h2>\n<p>Une interface peut remplacer une classe pour d\u00e9clarer :<\/p>\n<ul>\n<li>un attribut<\/li>\n<li>une variable<\/li>\n<li>un param\u00e8tre<\/li>\n<li>une valeur de retour<\/li>\n<\/ul>\n<p>&nbsp;<\/p>\n<p>Attention, on ne peut pas instancier une interface.<\/p>\n<pre><code class=\"java\" data-trim=\"\">\r\n      Comparable c = new Comparable(); \/\/ NON\r\n<\/code><\/pre>\n<\/section>\n<section>\n<h2>Exemple 3<\/h2>\n<pre><code class=\"java\" data-trim=\"\">\r\n    interface Comparable {\r\n    boolean greaterThan(Object o);\r\n}\r\nclass Maximize {\r\n    static public Comparable max(Comparable a, Comparable b) {\r\n        if(a.greaterThan(b)) {\r\n            return a;\r\n        }\r\n        return b;\r\n    }\r\n}\r\n\r\nclass ListElements {\r\n\tComparable[] tab;\r\n\tint nbElements = 0;\r\n\r\n\tpublic ListElements(int maxSize) {\r\n\t\ttab = new Comparable[maxSize];\r\n\t}\r\n\r\n\tpublic void add(Comparable e) {\r\n\t\ttab[nbElements] = e;\r\n\t\tnbElements++ ;\r\n\t}\r\n\tpublic boolean isIncreasing() {\r\n\t\tfor (int i = 1; i &lt; nbElements ; i++) {\r\n\t\t\tif (tab[i-1].greaterThan(tab[i])) return false;\r\n\t\t}\r\n\t    return true;\r\n\t}\r\n}\r\n\r\nclass Person implements Comparable {\r\n    private int size;\r\n    Person(int size) { this.size = size; }\r\n    @Override\r\n    public String toString() { return \"size: \"+size; }\r\n    public boolean greaterThan(Object o) {\r\n        return this.size &gt; ((Person)o).size;\r\n    }\r\n}\r\npublic class Main {\r\n    static public void main(String[] args) {\r\n        Person p1 = new Person(157);\r\n        Person p2 = new Person(173);\r\n        Person p3 = new Person(175);\r\n        ListElements l = new ListElements(10);\r\n        l.add(p1);\r\n        l.add(p2);\r\n        l.add(p3);\r\n        System.out.println(l.isIncreasing());\r\n        l.add(p2);\r\n        System.out.println(l.isIncreasing());\r\n    }\r\n}\r\n<\/code><\/pre>\n<p><a href=\"https:\/\/repl.it\/DRGj\/2\" target=\"_blank\" rel=\"noopener\">run it<\/a><\/section>\n<section>\n<h2>Exemple 4 &#8211; Java 8 Interfaces<\/h2>\n<pre><code class=\"java\" data-trim=\"\">\r\npublic interface InterfaceA {\r\n    public default void foo() {\r\n        System.out.println(\"A -&gt; foo()\");\r\n    }\r\n}\r\n \r\npublic interface InterfaceB {\r\n    public default void foo1() {\r\n        System.out.println(\"B -&gt; foo()\");\r\n    }\r\n}\r\n \r\nprivate class Test implements InterfaceA, InterfaceB { \r\n.....\r\n}\r\n<\/code><\/pre>\n<p>Les m\u00e9thodes &#8220;foo&#8221; et &#8220;foo1&#8221; par d\u00e9faut sont appelables dans la classe Test.<\/p>\n<\/section>\n<section>\n<h2>Exemple 4 &#8211; Java 8 Interfaces<\/h2>\n<pre><code class=\"java\" data-trim=\"\">\r\npublic interface InterfaceA {\r\n    public default void foo() {\r\n        System.out.println(\"A -&gt; foo()\");\r\n    }\r\n}\r\n \r\npublic interface InterfaceB {\r\n    public default void foo() {\r\n        System.out.println(\"B -&gt; foo()\");\r\n    }\r\n}\r\n \r\nprivate class Test implements InterfaceA, InterfaceB {\r\n    \/\/ Erreur de compilation : \"class Test inherits unrelated defaults for foo() from types InterfaceA and InterfaceB\"\r\n}\r\n<\/code><\/pre>\n<\/section>\n<section>\n<h2>Exemple 4 &#8211; Java 8 Interfaces &#8211; Solution<\/h2>\n<pre><code class=\"java\" data-trim=\"\">\r\n   public class Test implements InterfaceA, InterfaceB {\r\n     public void foo() {\r\n        System.out.println(\"Test -&gt; foo()\");\r\n    }\r\n}\r\n<\/code><\/pre>\n<p>La m\u00e9thode &#8220;foo&#8221; par d\u00e9faut n&#8217;est plus appelable directement. L&#8217;appel de cette m\u00e9thode se r\u00e9alise en utilisant Interface.super.m\u00e9thode.<\/p>\n<pre><code class=\"java\" data-trim=\"\">\r\npublic class Test implements InterfaceA, InterfaceB {\r\n     public void foo() {\r\n        InterfaceB.super.foo();\r\n    }\r\n}\r\n\r\n<\/code><\/pre>\n<\/section>\n<\/section>\n<section>\n<section class=\"toc-pause\">\n<h1>M\u00e9thodes et Classes Abstraites<\/h1>\n<\/section>\n<section>\n<h2>M\u00e9thodes Abstraites<\/h2>\n<p>Lorsqu&#8217;on cr\u00e9e une hi\u00e9rarchie de classes (pensez aux animaux), il y a certaines m\u00e9thodes difficiles \u00e0 d\u00e9finir dans les classes trop g\u00e9n\u00e9rales.<\/p>\n<p class=\"fragment\">Dans la classe <code>Animal<\/code>, par exemple, comment d\u00e9finir la m\u00e9thode <code>manger<\/code>.<\/p>\n<pre class=\"fragment\"><code class=\"java\" data-trim=\"\">\r\npublic class Animal {\r\n     ...\r\n     public void manger(Nourriture n) {\r\n         \/\/ Que faire?\r\n     }\r\n}                        <\/code><\/pre>\n<\/section>\n<section>\n<h2>M\u00e9thodes Abstraites<\/h2>\n<p>Dans ce cas, on peut d\u00e9finir une m\u00e9thode abstraite avec le mot cl\u00e9 <code>abstract<\/code>.<\/p>\n<pre class=\"fragment\"><code class=\"java\" data-trim=\"\">\r\npublic abstract class Animal {\r\n     ...\r\n     public abstract void manger(Nourriture n);\r\n     \/\/ pas de code associe\u0301\r\n}                        <\/code><\/pre>\n<p class=\"fragment\">Une m\u00e9thode abstraite <b>doit obligatoirement \u00eatre red\u00e9finie dans les classes d\u00e9riv\u00e9es.<\/b><\/p>\n<p>c&#8217;est exactement comme pour les m\u00e9thodes d\u00e9finies par une interface. <b>Les m\u00e9thodes d&#8217;une interface sont d&#8217;ailleurs aussi appel\u00e9es &#8220;m\u00e9thodes abstraites&#8221;.<\/b><\/p>\n<\/section>\n<section>\n<h2>Classe Abstraites<\/h2>\n<p>Une classe qui contient une m\u00e9thode abstraite, est aussi abstraite, et doit \u00eatre <b>d\u00e9clar\u00e9e comme telle<\/b>.<\/p>\n<pre class=\"fragment\"><code class=\"java\" data-trim=\"\">\r\npublic abstract class Animal {\r\n     ...\r\n     public abstract void manger(Nourriture n);\r\n     \/\/ pas de code associe\u0301\r\n}                        <\/code><\/pre>\n<p class=\"fragment\">Comme pour les interfaces, <b>on ne peut pas instancier une classe abstraite<\/b><\/p>\n<\/section>\n<section>\n<h2>Classe Abstraite<\/h2>\n<pre><code class=\"java\" data-trim=\"\">\r\npublic class Lion extends Mammife\u0300re {\r\n    ...\r\n    @Override\r\n    public void manger(Nourriture n) {\r\n        \/\/ code spe\u0301cifique aux lions\r\n    }\r\n}\r\n                        <\/code><\/pre>\n<\/section>\n<section>\n<h2>Classe Abstraite, Remarques<\/h2>\n<p class=\"fragment\">A la diff\u00e9rence d&#8217;une interface, une classe abstraite peut contenir des m\u00e9thodes concr\u00e8tes (non-abstraites).<\/p>\n<p class=\"fragment\">Une classe abstraite peut ne pas contenir de m\u00e9thodes abstraites.<\/p>\n<\/section>\n<section>\n<h2>Instanciation et Sp\u00e9cialisation<\/h2>\n<p>Comme avec une interface, une classe abstraite constitue un type a\u0300 part enti\u00e8re, mais qui ne peut pas \u00eatre instanci\u00e9e :<\/p>\n<pre class=\"fragment\"><code class=\"java\" data-trim=\"\">\r\nAnimal unAnimal; \/\/ OK\r\nunAnimal = new Animal (...); \/\/ ERREUR\r\n                        <\/code><\/pre>\n<p class=\"fragment\">Une sous-classe d\u2019une classe abstraite peut :<\/p>\n<ul>\n<li class=\"fragment\">impl\u00e9menter toutes les m\u00e9thodes abstraites. Elle pourra alors \u00eatre d\u00e9clar\u00e9e comme concr\u00e8te et donc instanci\u00e9e.<\/li>\n<li class=\"fragment\">ne pas impl\u00e9menter toutes ces m\u00e9thodes abstraite. Elle reste alors n\u00e9cessairement abstraite et ne pourra \u00eatre instanci\u00e9e.<\/li>\n<li class=\"fragment\">ajouter d\u2019autre(s) m\u00e9thode(s) abstraite(s). Elle reste alors n\u00e9cessairement abstraite et ne pourra \u00eatre instanci\u00e9e.<\/li>\n<\/ul>\n<p>&nbsp;<\/p>\n<\/section>\n<section>\n<h2>Classe Abstraite<\/h2>\n<p>Les classes abstraites sont entre les classes concr\u00e8tes et les interfaces.<\/p>\n<p>On les utilise :<\/p>\n<ul>\n<li>lorsqu&#8217;on a besoin de l&#8217;h\u00e9ritage (r\u00e9utilisation du code ; m\u00e9thodes concr\u00e8tes dans la classe de base qui fonctionnent de la m\u00eame mani\u00e8re quelque soit les classes d\u00e9riv\u00e9es).<\/li>\n<li>mais que certaines m\u00e9thodes n&#8217;ont pas de sense \u00e0 \u00eatre d\u00e9finie<\/li>\n<\/ul>\n<p>&nbsp;<\/p>\n<\/section>\n<\/section>\n<section>\n<section class=\"toc-pause\">\n<h1>Exemple de Classe Abstraite<\/h1>\n<\/section>\n<section>\n<h2>Exemple<\/h2>\n<p>Probl\u00e8me : faire un syst\u00e8me permettant de repr\u00e9senter des formes g\u00e9om\u00e9triques dans un terminal. Toutes les formes g\u00e9om\u00e9triques doivent avoir une couleur de fond, une couleur de bordure et une largeur de bordure.<\/p>\n<p class=\"fragment\">Solution : D\u00e9finir une classe <code>Shape<\/code> qui permet des g\u00e9rer tous ce que les figures ont en commun. <code>Shape<\/code> doit avoir une m\u00e9thode abstraite <code>contains(int x, int y)<\/code> pour savoir si un pixel appartient \u00e0 la figure.<\/p>\n<\/section>\n<section>\n<h2>La Classe <code>Shape<\/code><\/h2>\n<pre><code class=\"java\" data-trim=\"\">\r\npublic abstract class Shape {\r\n    private char fillColor, strokeColor;\r\n    private int strokeWidth;\r\n\r\n\r\n    public Shape() {\r\n\r\n    }\r\n    public Shape(char fillColor, char strokeColor, int strokeWidth) {\r\n        this.fillColor = fillColor;\r\n        this.strokeColor = strokeColor;\r\n        this.strokeWidth = strokeWidth;\r\n    }\r\n\r\n    public void setFillColor(char b) { fillColor = b; }\r\n    public void setStrokeColor(char b) { strokeColor = b; }\r\n    public void setStrokeWidth(int w) { strokeWidth = w; }\r\n\r\n    public char getFillColor() { return fillColor; }\r\n    public char getStrokeColor() { return strokeColor; }\r\n    public int getStrokeWidth() { return strokeWidth; }\r\n\r\n    abstract public boolean contains(int x, int y);\r\n\r\n    public boolean onStroke(int x, int y) {\r\n        if(contains(x, y)) return false;\r\n\r\n        for(int dx = -strokeWidth; dx &lt;= strokeWidth; ++dx) {\r\n            for(int dy = -strokeWidth; dy &lt;= strokeWidth; ++dy) {\r\n                if(contains(x + dx, y + dy)) return true;\r\n            }\r\n        }\r\n        return false;\r\n    }\r\n    @Override\r\n    public String toString() { return \"Shape\"; }\r\n}\r\n                        <\/code><\/pre>\n<\/section>\n<section>\n<h2>La Classe <code>Rectangle<\/code><\/h2>\n<pre><code class=\"java\" data-trim=\"\">\r\n\r\npublic class Rectangle extends Shape {\r\n    private int x, y, w, h;\r\n    public Rectangle(int x, int y, int w, int h) {\r\n        this.x = x;\r\n        this.y = y;\r\n        this.w = w;\r\n        this.h = h;\r\n    }\r\n    @Override\r\n    public boolean contains(int x, int y) {\r\n        return x &gt;= this.x &amp;&amp; x &lt; this.x + this.w &amp;&amp;\r\n               y &gt;= this.y &amp;&amp; y &lt; this.y + this.h;\r\n    }\r\n}\r\n\r\n                        <\/code><\/pre>\n<\/section>\n<section>\n<h2>La Classe <code>Circle<\/code><\/h2>\n<pre><code class=\"java\" data-trim=\"\">\r\npublic class Circle extends Shape {\r\n    private int x, y, radius;\r\n    public Circle(int x, int y, int radius) {\r\n        this.x = x;\r\n        this.y = y;\r\n        this.radius = radius;\r\n    }\r\n    @Override\r\n    public boolean contains(int x, int y) {\r\n        return (x-this.x)*(x-this.x) + (y - this.y)*(y - this.y) &lt; radius*radius;\r\n    }\r\n}\r\n                        <\/code><\/pre>\n<\/section>\n<\/section>\n<section>\n<section class=\"toc-pause\">\n<h1>Exemples de Hi\u00e9rarchies<\/h1>\n<\/section>\n<section>\n<h2>Probl\u00e8me de Figures avec Aires<\/h2>\n<p>Probl\u00e8me : on veut cr\u00e9er un programme qui calcule les aires d&#8217;un ensemble de figures. On veut pouvoir cr\u00e9er de nouvelles classes repr\u00e9sentant des figures donn\u00e9es. On veut donc que chaque figure poss\u00e8de une m\u00e9thode <code>getArea()<\/code> qui retourne cette aire.<\/p>\n<p class=\"fragment\">Solution : ici, inutile de cr\u00e9er une classe <code>Shape<\/code> car les figures n&#8217;auront rien en commun \u00e0 part une m\u00e9thode <code>getArea()<\/code>. Une interface <code>Measurable<\/code> par exemple est suffisante.<\/p>\n<\/section>\n<section>\n<h2>Classe et Interface<\/h2>\n<p>Parfois il est int\u00e9ressant de proposer \u00e0 la fois une classe abstraite et une interface pour mod\u00e9liser un comportement.<\/p>\n<p class=\"fragment\">On le retrouve souvent dans l&#8217;API standart de Java. <a href=\"https:\/\/docs.oracle.com\/javase\/7\/docs\/api\/java\/lang\/Runnable.html\" target=\"_blank\" rel=\"noopener\">Runnable<\/a> <a href=\"https:\/\/docs.oracle.com\/javase\/7\/docs\/api\/java\/util\/Collection.html\" target=\"_blank\" rel=\"noopener\">Collection<\/a><\/p>\n<\/section>\n<section>\n<h2>H\u00e9ritage et Composition<\/h2>\n<p>Parfois il est aussi pr\u00e9f\u00e9rable d&#8217;utiliser la composition. (exemple du copieur\/imprimante\/scanner).<\/p>\n<\/section>\n<section>\n<h2>H\u00e9ritage et Composition<\/h2>\n<p>Supposons qu&#8217;on veut enrichir une classe <code>ListProduct<\/code> (qui stocke des produits), afin qu&#8217;elle garde en m\u00e9moire la somme des prix des produits stock\u00e9s.<\/p>\n<p>On suppose que cette classe est propos\u00e9e par une biblioth\u00e8que et qu&#8217;on n&#8217;a pas acc\u00e8s au code source.<\/p>\n<pre><code class=\"java\" data-trim=\"\">\r\nclass Product {\r\n\tpublic int getPrice() { return 1; }\r\n}\r\nclass ListProduct {\r\n    ...\r\n    public ListProduct() {\r\n        ...\r\n    }\r\n    public void addAll(Product[] tab) {\r\n        ...\r\n    }\r\n    public void add(Product e) {\r\n    ...\r\n    }\r\n}\r\nclass AwesomeListProduct extends ListProduct {\r\n\r\n    private int totalPrice;\r\n    public void addAll(Product[] tab) {\r\n        super.addAll(tab);\r\n\r\n        for(Product p : tab) {\r\n            totalPrice += p.getPrice();\r\n        }\r\n    }\r\n    public void add(Product p) {\r\n        super.add(p);\r\n        totalPrice += p.getPrice();\r\n    }\r\n    public int getTotalPrice() { return totalPrice; }\r\n}\r\n                        <\/code><\/pre>\n<\/section>\n<section>\n<h2>H\u00e9ritage et Composition<\/h2>\n<pre><code class=\"java\" data-trim=\"\">\r\nclass Main {\r\n  public static void main(String[] args) {\r\n  \tAwesomeListProduct list = new AwesomeListProduct();\r\n\r\n  \tProduct[] tab = {new Product(), new Product()};\r\n  \tlist.addAll(tab);\r\n\r\n    System.out.println(list.getTotalPrice());\r\n\r\n  }\r\n}\r\n                        <\/code><\/pre>\n<p><a href=\"https:\/\/repl.it\/DWmg\" target=\"_blank\" rel=\"noopener\">run it!<\/a><\/p>\n<p class=\"fragment\">Qu&#8217;affiche se programme?<\/p>\n<pre class=\"fragment\"><code class=\"java\" data-trim=\"\">\r\n2\r\n                        <\/code><\/pre>\n<\/section>\n<section>\n<h2>H\u00e9ritage et Composition<\/h2>\n<p>En effet on ne sais pas comment est impl\u00e9ment\u00e9e la m\u00e9thode <code>addAll<\/code>. Dans ce cas, elle appelle la m\u00e9thode <code>add()<\/code>.<\/p>\n<pre class=\"fragment\"><code class=\"java\" data-trim=\"\">\r\nclass ListProduct {\r\n    private Product[] products;\r\n    private int nbProduct;\r\n    public ListProduct() {\r\n        products = new Product[10];\r\n    }\r\n    public void addAll(Product[] tab) {\r\n        for(Product e : tab) {\r\n            add(e);\r\n        }\r\n    }\r\n    public void add(Product e) {\r\n        products[nbProduct] = e;\r\n        nbProduct++;\r\n    }\r\n}\r\n                        <\/code><\/pre>\n<\/section>\n<section>\n<h2>H\u00e9ritage et Composition<\/h2>\n<p>En voyant \u00e7a, on peut se dire qu&#8217;on n&#8217;a juste \u00e0 enlever la red\u00e9finition de la m\u00e9thode <code>addAll()<\/code><\/p>\n<p class=\"fragment\">Cependant, notre classe va alors d\u00e9pendre de la mani\u00e8re dont la classe <code>ListProduct<\/code> est impl\u00e9ment\u00e9e.<\/p>\n<p class=\"fragment\">Si la librairie modifie l&#8217;impl\u00e9mentation de ces m\u00e9thodes, par exemple pour optimiser la m\u00e9thode <code>addAll()<\/code>. Notre classe pourrait ne plus fonctionner.<\/p>\n<\/section>\n<section>\n<h2>H\u00e9ritage et Composition<\/h2>\n<p><b>Il ne faut pas que notre programme d\u00e9pendent de l&#8217;impl\u00e9mentation interne des libraries utilis\u00e9es.<\/b><\/p>\n<p class=\"fragment\">Si possible les diff\u00e9rentes parties de notre programme doivent aussi \u00eatre ind\u00e9pendantes. Il faut \u00e9viter les d\u00e9pendances sur l&#8217;impl\u00e9mentation entre composants.<\/p>\n<\/section>\n<section>\n<h2>H\u00e9ritage et Composition<\/h2>\n<p>Comment faire alors?<\/p>\n<p class=\"fragment\">Dans ce cas on peut utiliser la composition.<\/p>\n<\/section>\n<section>\n<h2>H\u00e9ritage et Composition<\/h2>\n<pre><code class=\"java\" data-trim=\"\">\r\nclass AwesomeListProduct {\r\n    private ListProduct listProduct;\r\n    private int totalPrice;\r\n    public AwesomeListProduct() {\r\n        listProduct = new ListProduct();\r\n    }\r\n    public void addAll(Product[] tab) {\r\n        listProduct.addAll(tab);\r\n\r\n        for(Product p : tab) {\r\n            totalPrice += p.getPrice();\r\n        }\r\n    }\r\n    public void add(Product p) {\r\n        listProduct.add(p);\r\n        totalPrice += p.getPrice();\r\n    }\r\n    public int getTotalPrice() { return totalPrice; }\r\n}\r\n                        <\/code><\/pre>\n<\/section>\n<\/section>\n<section>\n<section class=\"toc-pause\">\n<h1>Enum\u00e9rations<\/h1>\n<\/section>\n<section>\n<h2>Utilit\u00e9<\/h2>\n<p>Prenons l&#8217;exemple du jeu du robot. Il serait int\u00e9ressant d&#8217;avoir une fonction qui permet de connaitre la direction du robot (haut, bas, gauche ou droite).<\/p>\n<p class=\"fragment\">Probl\u00e8me comment repr\u00e9senter cette direction?<\/p>\n<pre class=\"fragment\"><code class=\"java\" data-trim=\"\">\r\npublic ??? getDirection() {\r\n    ...\r\n}\r\n                        <\/code><\/pre>\n<\/section>\n<section>\n<h2>Utilit\u00e9<\/h2>\n<p>Probl\u00e8me comment repr\u00e9senter cette direction?<\/p>\n<ul>\n<li>Se mettre d&#8217;accord pour dire que : 1 signifie haut, 2 signifie bas, etc.<\/li>\n<\/ul>\n<p>&nbsp;<\/p>\n<pre class=\"fragment\"><code class=\"java\" data-trim=\"\">\r\npublic int getDirection() {\r\n    if(....)\r\n        return 1; \/\/ return UP\r\n    ...\r\n}\r\n                        <\/code><\/pre>\n<pre class=\"fragment\"><code class=\"java\" data-trim=\"\">\r\nif(robot.getDirection() == 1) {\r\n    ...\r\n}\r\n                        <\/code><\/pre>\n<p class=\"fragment\">Pas forc\u00e9ment facile de se rappeler des valeurs ; c&#8217;est source d&#8217;erreur.<\/p>\n<\/section>\n<section>\n<h2>Utilit\u00e9<\/h2>\n<p>Probl\u00e8me comment repr\u00e9senter cette direction?<\/p>\n<ul>\n<li>Utiliser une chaine de caract\u00e8res : &#8220;UP&#8221;, &#8220;DOWN&#8221;, &#8220;LEFT&#8221;, &#8220;RIGHT&#8221;<\/li>\n<\/ul>\n<p>&nbsp;<\/p>\n<pre class=\"fragment\"><code class=\"java\" data-trim=\"\">\r\npublic String getDirection() {\r\n    if(....)\r\n        return \"LEFT\";\r\n    ...\r\n}\r\n                        <\/code><\/pre>\n<pre class=\"fragment\"><code class=\"java\" data-trim=\"\">\r\nif(robot.getDirection() == \"LEFT\") {\r\n    ...\r\n}\r\n                        <\/code><\/pre>\n<p class=\"fragment\">Difficile de comprendre en regardant la signature de la m\u00e9thode ce qu&#8217;elle renvoie exactement.<\/p>\n<\/section>\n<section>\n<h2>Utilit\u00e9<\/h2>\n<p>Probl\u00e8me comment repr\u00e9senter cette direction?<\/p>\n<ul>\n<li>Utiliser une \u00e9num\u00e9ration.<\/li>\n<\/ul>\n<p>&nbsp;<\/p>\n<pre class=\"fragment\"><code class=\"java\" data-trim=\"\">\r\npublic Direction getDirection() {\r\n    if(....)\r\n        return Direction.LEFT;\r\n    ...\r\n}\r\n                        <\/code><\/pre>\n<pre class=\"fragment\"><code class=\"java\" data-trim=\"\">\r\nif(robot.getDirection() == Direction.LEFT) {\r\n    ...\r\n}\r\n                        <\/code><\/pre>\n<\/section>\n<section>\n<h2>D\u00e9finir une Enum\u00e9ration<\/h2>\n<p>On cr\u00e9e une \u00e9num\u00e9ration comme une classe<\/p>\n<pre class=\"fragment\"><code class=\"java\" data-trim=\"\">\r\npublic enum Direction {\r\n    UP,\r\n    RIGHT,\r\n    DOWN,\r\n    LEFT\r\n}\r\n<\/code><\/pre>\n<p class=\"fragment\">Comme une classe, \u00e7a d\u00e9finit un type!<\/p>\n<p class=\"fragment\">C&#8217;est un peu comme une classe mais qui ne contient des attributs <code>static<\/code> et <code>public<\/code>.<\/p>\n<p class=\"fragment\">On ne peut pas l&#8217;instancier et il y a un nombre fini d&#8217;objets <b>qui existent d\u00e9j\u00e0<\/b> et qu&#8217;on peut utiliser.<\/p>\n<\/section>\n<section>\n<h2>Utiliser une Enum\u00e9ration<\/h2>\n<pre><code class=\"java\" data-trim=\"\">\r\npublic enum Direction {\r\n    UP,\r\n    RIGHT,\r\n    DOWN,\r\n    LEFT\r\n}\r\n<\/code><\/pre>\n<pre><code class=\"java\" data-trim=\"\">\r\nDirection d = Direction.UP;\r\nSystem.out.println(d); \/\/ affiche UP\r\nSystem.out.println(d == Direction.UP);\r\nswitch(d) {\r\n    case UP: d = Direction.LEFT; break;\r\n    case LEFT: d = Direction.DOWN; break;\r\n    case DOWN: d = Direction.RIGHT; break;\r\n    case RIGHT: d = Direction.UP; break;\r\n}\r\nSystem.out.println(d);\r\n<\/code><\/pre>\n<\/section>\n<section>\n<h2>Lister les valeurs possibles<\/h2>\n<p>la m\u00e9thode <code>values()<\/code> permet de lister les valeurs possibles :<\/p>\n<pre><code class=\"java\" data-trim=\"\">\r\nfor(Direction d : Direction.values()){\r\n    System.out.println(d);\r\n}\r\n                        <\/code><\/pre>\n<\/section>\n<section>\n<h2>Conversion depuis une chaine de caract\u00e8res<\/h2>\n<pre class=\"fragment hide-with-next-fragment\"><code class=\"java\" data-trim=\"\">\r\nScanner sc = new Scanner(System.in);\r\n\r\nString text = sc.next(); \/\/ lit une direction au clavier, ex: UP\r\nDirection d = ...\r\n\r\nSystem.out.println(d); \/\/ affiche UP\r\n                        <\/code><\/pre>\n<pre class=\"fragment hide-with-next-fragment\"><code class=\"java\" data-trim=\"\">\r\nScanner sc = new Scanner(System.in);\r\n\r\nString text = sc.next(); \/\/ lit une direction au clavier, ex: UP\r\nDirection d;\r\nif(text.equals(\"UP\")) {\r\n    d = Direction.UP;\r\n} else\r\n...\r\n\r\nSystem.out.println(d); \/\/ affiche UP\r\n                        <\/code><\/pre>\n<pre class=\"fragment hide-with-next-fragment\"><code class=\"java\" data-trim=\"\">\r\nScanner sc = new Scanner(System.in);\r\n\r\nString text = sc.next(); \/\/ lit une direction au clavier, ex: UP\r\nDirection d;\r\nfor(Direction t : Direction.values()) {\r\n    if(t.toString().equals(text)) {\r\n        d = t;\r\n    }\r\n}\r\nSystem.out.println(d); \/\/ affiche UP\r\n                        <\/code><\/pre>\n<pre class=\"fragment\"><code class=\"java\" data-trim=\"\">\r\nScanner sc = new Scanner(System.in);\r\n\r\nString text = sc.next(); \/\/ lit une direction au clavier, ex: UP\r\nDirection d = Direction.valueOf(text);\r\nSystem.out.println(d); \/\/ affiche UP\r\n                        <\/code><\/pre>\n<p class=\"fragment\">Pour convertir une chaine de caract\u00e8re en valeur d&#8217;\u00e9num\u00e9ration, il faut utiliser la m\u00e9thode <code>valueOf()<\/code>.<\/p>\n<\/section>\n<section>\n<h2>Enum\u00e9ration plus complexes<\/h2>\n<p>Comme pour les classes, on peut aussi ajouter des attributs et des m\u00e9thodes.<\/p>\n<pre><code class=\"java\" data-trim=\"\">\r\nenum Direction {\r\n    UP(\"\u2191\"),\r\n    RIGHT(\"\u2192\"),\r\n    DOWN(\"\u2193\"),\r\n    LEFT(\"\u2190\");\r\n\r\n    private String arrow;\r\n    Direction(String arrow) {\r\n    \tthis.arrow = arrow;\r\n    }\r\n    public String toArrow() { return arrow; }\r\n}\r\n                        <\/code><\/pre>\n<p><small>Si on d\u00e9finit un constructeur n\u00e9cessitant des arguments, ces-derniers doivent \u00eatre fournit lors de l&#8217;\u00e9num\u00e9ration des valeurs possibles.<\/small><\/p>\n<p><a href=\"https:\/\/repl.it\/DXSY\" target=\"_blank\" rel=\"noopener\">run it!<\/a><\/section>\n<section>\n<h2>Retour sur l&#8217;exemple des figures<\/h2>\n<pre class=\"fragment\"><code class=\"java\" data-trim=\"\">\r\n\r\npublic enum ConsoleColor {\r\n    BLACK('0'),\r\n    RED('1'),\r\n    GREEN('2'),\r\n    WHITE('7');\r\n\r\n      private char code = '0';\r\n\r\n      ConsoleColor(char code){\r\n        this.code = code;\r\n      }\r\n\r\n      public char code(){\r\n        return code;\r\n      }\r\n\r\n      public String apply(String s) {\r\n          return \"\\u001B[3\" + code() + \"m\" + s + \"\\u001B[0m\";\r\n      }\r\n}\r\n\r\n                        <\/code><\/pre>\n<\/section>\n<\/section>\n<section>\n<section class=\"toc-pause\">\n<h1>Package et Jar<\/h1>\n<\/section>\n<section>\n<h2>Package et Jar<\/h2>\n<p>Vous avez vu qu&#8217;un package dans un dossier n&#8217;est pas facile \u00e0 distribuer.<\/p>\n<p>C&#8217;est pourquoi on peut cr\u00e9er, \u00e0 partir d&#8217;un dossier qui contient un package, un fichier <code>Jar<\/code> (Java Archive). Plus facile \u00e0 distribuer et \u00e0 utiliser (notamment avec eclipse).<\/p>\n<\/section>\n<section>\n<h2>Package et Jar<\/h2>\n<p>On cr\u00e9ee un <code>Jar<\/code> avec la commande <code>jar<\/code>.<\/p>\n<p>Cette commande accepte les op\u00e9rations <code>c<\/code>, <code>t<\/code>, et <code>x<\/code> ainsi que les options <code>v<\/code> (pour afficher les d\u00e9tails) et <code>f<\/code> (pour indiquer le nom du fichier Jar).<\/p>\n<\/section>\n<section>\n<h2>Package et Jar<\/h2>\n<p>&nbsp;<\/p>\n<ul>\n<li><code>c<\/code> : Pour cr\u00e9er une archive. On indique le dossier contenant le package<\/li>\n<\/ul>\n<p>&nbsp;<\/p>\n<pre><code class=\"java\" data-trim=\"\">\r\njar cvf RobotGame.jar -C dossier\/contenant\/les\/classes .\r\n                        <\/code><\/pre>\n<\/section>\n<section>\n<h2>Package et Jar<\/h2>\n<p>&nbsp;<\/p>\n<ul>\n<li><code>c<\/code> : Pour cr\u00e9er une archive. On indique le dossier contenant le dossier contenant le package<\/li>\n<li><code>t<\/code> : Pour afficher le contenu d&#8217;une archive<\/li>\n<\/ul>\n<p>&nbsp;<\/p>\n<pre><code class=\"java\" data-trim=\"\">\r\njar tf RobotGame.jar\r\n                        <\/code><\/pre>\n<\/section>\n<section>\n<h2>Package et Jar<\/h2>\n<p>&nbsp;<\/p>\n<ul>\n<li><code>c<\/code> : Pour cr\u00e9er une archive. On indique le dossier contenant le dossier contenant le package<\/li>\n<li><code>t<\/code> : Pour afficher le contenu d&#8217;une archive<\/li>\n<li><code>x<\/code> : Pour extraire une archive<\/li>\n<\/ul>\n<p>&nbsp;<\/p>\n<pre><code class=\"java\" data-trim=\"\">\r\njar xf RobotGame.jar\r\n                        <\/code><\/pre>\n<\/section>\n<section>\n<h2>Comment organiser un Projet?<\/h2>\n<p>Le mieux est de s\u00e9parer les sources et les fichiers compil\u00e9s.<\/p>\n<p>Dans un dossier vide, on cr\u00e9e un dossier <code>src<\/code> qui va contenir nos fichiers sources, et un dossier <code>bin<\/code> qui va contenir nos fichiers compil\u00e9s.<\/p>\n<\/section>\n<section>\n<h2>Organisation d&#8217;un projet<\/h2>\n<p>Pour mon package <code>fr.dant.robotgame<\/code>, j&#8217;ai mes sources dans un dossier <code>src\/fr\/dant\/robotgame<\/code><\/p>\n<p>Je peux les compiler et placer les fichiers compil\u00e9s dans le r\u00e9pertoire donn\u00e9.<\/p>\n<pre><code class=\"bash\" data-trim=\"\">\r\njavac -d .\/bin -cp .\/bin src\/fr\/dant\/robotgame\/*.java\r\n                        <\/code><\/pre>\n<p>Et finalement cr\u00e9er le fichier <code>Jar<\/code> :<\/p>\n<pre><code class=\"bash\" data-trim=\"\">\r\njar cvf RobotGame.jar -C bin .\r\n                        <\/code><\/pre>\n<\/section>\n<section>\n<h2>MANIFEST<\/h2>\n<p>Le fichier MANIFEST.MF contient l\u2019ensemble des m\u00e9tadonn\u00e9es d\u2019une archive jar sous forme d\u2019un unique fichier texte stock\u00e9 dans le r\u00e9pertoire META-INF.<\/p>\n<p>Il peut contenir entre autre :<br \/>\n<b>Manifest-Version<\/b> : num\u00e9ro de version<br \/>\n<b>Created-By<\/b> : nom de l\u2019auteur<br \/>\n<b>Class-Path<\/b> : nom d\u2019autre archive contenant des d\u00e9pendances<br \/>\n<b>Main-Class<\/b> : nom de la classe contenant la main \u00e0 ex\u00e9cuter.<\/p>\n<\/section>\n<section>\n<h2>MANIFEST<\/h2>\n<p>Exemple :<\/p>\n<pre><code class=\"ini\">Manifest-Version: 1.0\r\nCreated-By: Quentin Bramas\r\nMain-Class: RobotGame\r\n\r\n<\/code><\/pre>\n<p>Attention : Le fichier MANIFEST doit obligatoirement :<br \/>\n\u00eatre encod\u00e9 en UTF8 ;<br \/>\nse terminer par un retour \u00e0 la ligne (derni\u00e8re ligne vide) ;<br \/>\nn\u2019avoir aucun espace \u00e0 la fin des diff\u00e9rentes lignes.<\/p>\n<\/section>\n<section>\n<h2>MANIFEST<\/h2>\n<p>L\u2019option <code>m<\/code> permet de fournir un MANIFEST.MF a\u0300 la cr\u00e9ation du jar :<\/p>\n<pre><code class=\"bash\" data-trim=\"\">\r\n                        jar cvmf src\/MANIFEST.MF RobotGame.jar -C bin .<\/code><\/pre>\n<\/section>\n<\/section>\n","protected":false},"excerpt":{"rendered":"<p>Interfaces H\u00e9ritage et Sous-Type On a vu l&#8217;int\u00e9r\u00eat de l&#8217;h\u00e9ritage et du polymorphisme pour le sous-typage. Animal a1 = Math.random() &lt; 0.5 ? new Dog() : new Cat(); a1.speak(); Ce qui permet l&#8217;utilisation de variables de type g\u00e9n\u00e9rique, pouvant stocker des objets qu&#8217;on utilise quelque soit leur type. Ceci est rendu possible par la red\u00e9finition [&hellip;]<\/p>\n","protected":false},"author":55,"featured_media":0,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[1],"tags":[],"class_list":["post-53","post","type-post","status-publish","format-standard","hentry","category-uncategorized"],"_links":{"self":[{"href":"https:\/\/wp-systeme.lip6.fr\/potop-butucaru\/wp-json\/wp\/v2\/posts\/53","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/wp-systeme.lip6.fr\/potop-butucaru\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/wp-systeme.lip6.fr\/potop-butucaru\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/wp-systeme.lip6.fr\/potop-butucaru\/wp-json\/wp\/v2\/users\/55"}],"replies":[{"embeddable":true,"href":"https:\/\/wp-systeme.lip6.fr\/potop-butucaru\/wp-json\/wp\/v2\/comments?post=53"}],"version-history":[{"count":1,"href":"https:\/\/wp-systeme.lip6.fr\/potop-butucaru\/wp-json\/wp\/v2\/posts\/53\/revisions"}],"predecessor-version":[{"id":54,"href":"https:\/\/wp-systeme.lip6.fr\/potop-butucaru\/wp-json\/wp\/v2\/posts\/53\/revisions\/54"}],"wp:attachment":[{"href":"https:\/\/wp-systeme.lip6.fr\/potop-butucaru\/wp-json\/wp\/v2\/media?parent=53"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/wp-systeme.lip6.fr\/potop-butucaru\/wp-json\/wp\/v2\/categories?post=53"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/wp-systeme.lip6.fr\/potop-butucaru\/wp-json\/wp\/v2\/tags?post=53"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}