image/svg+xml $ $ ing$ ing$ ces$ ces$ Res Res ea ea Res->ea ou ou Res->ou r r ea->r ch ch ea->ch r->ces$ r->ch ch->$ ch->ing$ T T T->ea ou->r

L'objet

Un objet sert à modéliser une réalité, il possède :

Exemple : manipulons des points

Point p1 = new Point(0, 0);
Point p2 = new Point(0, 0);
Point p3 = new Point(0, 1);
Pixel p4 = new Pixel(0, 1);

Le modèle

Une représentation de la réalité

  1. Cette représentation peut être plus ou moins utilisable selon les applications
    1. Il faut donc concevoir le modèle avec pour finalité une application donnée
  2. Le modèle est toujours une approximation de la réalité (simplification), ne rendant pas compte de son infinie complexité
    1. Un modèle peut être plus précis mais au prix d'une implantation plus ardue
    2. Il faut trouver un compromis
    3. L'idéal est de partir d'un modèle grossier pour le raffiner ensuite incrémentalement
  3. Le modèle ne doit pas être figé
    1. Il faut le concevoir avec pour principal préoccupation son évolutivité
  4. Le modèle doit être réutilisable dans différents contextes
    1. La conception doit donc être modulaire avec une séparation en différents composants présentant un couplage faible

Différents points de vue, différents modèles

Selon les problèmes à résoudre, un modèle peut être privilégié plus qu'un autre (difficulté d'unifier des modèles différents).

La classe

Classes et modèle

Autres méthodes de modélisation

Une méthode de modélisation s'intéresse à un aspect plus ou moins spécifique du logiciel

Intérêt de UML : modélisation graphique pour des systèmes orientés objets plus conviviale qu'une représentation formelle (mais moins précise)

Éléments essentiels d'un diagramme de classes UML

La classe

Les relations

Relation d'association

Exemple : arbre généalogique (association reflexive)

Relations d'association forte

On peut renforcer la relation d'association par la composition et l'aggrégation.

Agrégation

Exemple d'association avec une voiture qui possède 4 roues voire 5 avec la roue de secours :

Composition

Relation de dépendance

Exemple avec une voiture ayant besoin d'une station service pour remplir son réservoir (on utilise GasStation dans l'implantation de la méthode fillTank)Station à essence

  1. ++ Relation de généralisation/spécialisation +++umlSpecialization

Relation de réalisation

Modèle et codage

Du code au modèle

Il existe des outils permettant de créer des diagrammes de classes à partir de code déjà réalisé (cela ne présente pas de difficultés majeures)

Du modèle au code

Des tentatives ont été réalisées afin de générer automatiquement du code-source à partir de modèles indépendants de langages :

Champs et méthodes statiques

Statique vs. non-statique

Utilité des membres statiques :

Un exemple avec des voitures

Le gouvernement de Syldavie septentrionale nous a chargé de concevoir un système d'immatriculation pour ses voitures. Chaque voiture doit avoir une immatriculation unique. Nous choisissons le schéma d'immatriculation le plus simple : chaque voiture est identifiée par un entier séquentiel (1ère voiture : 0, 2ème voiture : 1...). Nous implantons à cet effet une classe SyldavianCar :

/** A car registred in North-Syldavia */
public class SyldavianCar
{
	/** The registration number cannot change, thus it is final */
	private final int registrationNumber;
	
	/** This is the next registration number to attribute: it is static because shared for all the instances; 
	 *  it is an attribute of the class itself used to construct a new instance 
	 */
	private static int nextRegistrationNumber;
	
	public SyldavianCar()
	{
		this.registrationNumber = attributeRegistrationNumber();
	}
	
	public int getRegistrationNumber()
	{
		return this.registrationNumber;
	}
	
	/** Get the next available registration number
	 * it is private since only this current class require access to this method (used only by the constructor) 
	 */
	private static int attributeRegistrationNumber()
	{
		return nextRegistrationNumber++;
	}
}

Nous pouvons représenter la classe SyldavianCar par un modèle UML :Voiture syldave

On remarque que les membres statiques de la classe sont soulignés dans le modèle UML.

Mécanisme d'héritage

Présentation

En résumé, l'héritage recouvre deux notions :

Exemple de classe héritée

public class ColoredPoint extends Point
{
	public static final Point BLACK_ORIGIN =
		new ColoredPoint(0, 0);
		
	private Color color;
	
	public ColoredPoint(int x, int y, Color color)
	{
		super(x, y); // we call the constructor from the parent class
		this.color = color;
	}
	
	public ColoredPoint(int x, int y)
	{
		this(x, y, Color.BLACK);
	}
	
	public Color getColor()
	{
		return color;
	}
	
	public void setColor(Color c)
	{
		this.color = color;
	}
}

ColoredPoint cp = new ColoredPoint(0, 0, new Color(0.5, 0.5, 0.5);
Point p = cp;
Object o = p;
ColoredPoint cp2 = (ColoredPoint)o;
Point point = new Point(0, 0);
ColoredPoint cp3 = (ColoredPoint)point;
Parrot p = (Parrot)cp3;

A propos des constructeurs :

Redéfinition

Crééons maintenant une nouvelle classe héritant de ColoredPoint pour des points ne pouvant prendre qu'une couleur grise :

public final class GrayPoint extends ColoredPoint
{
	private float grayLevel;
	
	public GrayPoint(int x, int y, float grayLevel)
	{
		super(x, y, null);
	}
	
	public float getGrayLevel()
	{
		return grayLevel;
	}

	@Override
	public Color getColor()
	{
		return new Color(grayLevel, grayLevel, grayLevel);
	}
}

Nous avons actuellement l'arbre d'héritage suivant :

Object <-- Point <-- ColoredPoint <-- GrayPoint

Classe abstraite

Implantons une classe AbstractColoredPoint abstraite :

public abstract class AbstractColoredPoint extends Point
{
	public AbstractColoredPoint(int x, int y)
	{
		super(x, y);
	}
	
	public abstract Color getColor();
	
	public Color getNegativeColor()
	{
		final Color c = getColor();
		return new Color(255 - c.getRed(), 255 - c.getGreen(), 255 - c.getBlue()); 
	}
	
	@Override
	public String toString()
	{
		return "(" + x + "," + y + "," + getColor() + ")";
	}
}

On peut maintenant créer deux classes dérivées de AbstractColoredPoint GeneralColoredPoint pour représenter des points de couleur arbitraire et GrayColoredPoint pour représenter des points en niveau de gris :

public class GeneralColoredPoint extends AbstractColoredPoint
{
	private Color color;
	
	public ColoredPoint(int x, int y, Color color)
	{
		super(x, y);
		this.color = color;
	}
	
	@Override
	public Color getColor()
	{
		return color;
	}
	
	public void setColor(Color c)
	{
		this.color = color;
	}
}

public GrayColoredPoint extends AbstractColoredPoint
{
	private float grayLevel;
	
	public GrayColoredPoint(int x, int y, float grayLevel)
	{
		super(x, y);
		this.grayLevel = grayLevel;
	}
	
	@Override
	public Color getColor()
	{
		return new Color(grayLevel, grayLevel, grayLevel);
	}
	
	public void setGrayLevel(float grayLevel)
	{
		this.grayLevel = grayLevel;
	}

Polymorphisme (surcharge)

Écrivons maintenant une classe utilitaire avec des méthodes statiques pour réaliser des opérations sur les points :

public class Points
{
	/** Compute a segment with all the discrete points between the two points given as arguments
	 * @param start the start point
	 * @param stop the stop point
	 * @return an array including all the points of the segment
	 */
	public static Point[] computeSegment(Point start, Point stop)
	{
		int deltaX = stop.getX() - start.getX();
		int deltaY = stop.getY() - start.getY();
		boolean xAxis = deltaX > deltaY; // is the segment along the x axis?
		Point[] segment = new Point[Math.max(Math.abs(deltaX), Math.abs(deltaY)) + 1];
		for (int i = 0; i < segment.length; i++)
		{
			double position = (double)i / segment.length;
			segment[i] = new Point(start.x + deltaX * position, start.y + deltaY * position);
		}
		return segment;
	}
}

On souhaite maintenant écrire une méthode getSegment pour obtenir un segment entre deux points colorés avec un degradé progressif de couleur. On rajoute la méthode suivante dans la classe Points :

/** Compute a segment of interpolated points between the two points
 * The colors of the interpolated points follows a linear gradient
 */
public static AbstractColoredPoint[] computeSegment(AbstractColoredPoint start, AbstractColoredPoint stop)
{
	Point[] uncoloredSegment = computeSegment((Point)start, (Point)stop);
	AbstractColoredPoint[] coloredSegment = new AbstractColoredPoint[uncoloredSegment.length];
	int deltaR = stop.getColor().getRed() - start.getColor().getRed();
	int deltaG = stop.getColor().getGreen() - start.getColor().getGreen();
	int deltaB = stop.getColor().getBlue() - start.getColor().getBlue();
	for (int i = 0; i < uncoloredSegment.length; i++)
	{
		double position = (double)i / segment.length;
		Point uncoloredPoint = uncoloredSegment[i];
		coloredSegment[i] = new GeneralColoredPoint(
			uncoloredPoint.getX(), uncoloredPoint.getY(),
			new Color(
				start.getColor().getRed() + deltaR * position, 
				start.getColor().getGreen() + deltaG * position, 
				start.getColor().getBlue() + deltaB * position));
	}
}

Quel va être le résultat de ces instructions ?

Point a = new GrayColoredPoint(0, 0, 0.5);
Point b = new Point(10, 10);
Point c = new GeneralColoredPoint(5, 5, new Color(1.0, 0.0, 0.0));
Point[] firstSegment = Points.computeSegment(a, b);
Point[] secondSegment = Points.computeSegment(a, c);
Point[] thirdSegment = Points.computeSegment((GrayColoredPoint)a, (GeneralColoredPoint)c);

Écrivons maintenant dans la classe Points deux nouvelles méthodes :

Quelle méthode est appelée par cette instruction ?
Point[] segment = Points.computeSegment((GrayColoredPoint)a, (GeneralColoredPoint)c);

Les interfaces

Définissons par exemple les interfaces suivantes :

public interface Colored
{
	public Color getColor();
}

public interface Has2DCoordinates
{
	public int getX();
	public int getY();
}

On peut alors redéclarer Point :
public class Point implements Has2DCoordinates
Ainsi que AbstractColoredPoint :
public class AbstractColoredPoint extends Point implements Colored

La visibilité

Les constructeurs, champs et méthodes peuvent être accessibles ou non selon les contextes. On utilise des modificateurs de visibilité (du plus visible au moins visible) :

La délégation et la composition

Il est possible d'implanter des fonctionnalités pour une classe :

Par exemple, implantons GeneralColoredPoint en utilisant un mécanisme de composition :

public class GeneralColoredPoint implements Colored, Has2DCoordinates
{
	final private Point point;
	final private Color color;
	
	public GeneralColoredPoint(Point point, Color color)
	{
		this.point = point;
		this.color = color;
	}
	
	@Override
	public Color getColor() { return color; }
	
	@Override
	public int getX() { return point.getX(); }
	
	@Override
	public int getY() { return point.getY(); }
}

Test du type réel à l'exécution

Random r = new Random();
Point p = null;
if (r.nextInt(2) == 0)
	p = new Point(0, 0);
else
	p = new GrayColoredPoint(0, 0, 0.5);
// What is the real type of p?

Pour tester le type réel :

Le test de type réel d'exécution est généralement évitable (et doit être évité si possible).

Remarque : la méthode getClass() est implantée par la classe Object ; elle permet d'obtenir à l'exécution la classe d'un objet. Elle retourne une Class disposant de méthodes offrants des mécanismes d'introspection (liste de champs, méthodes, instantiation d'objets...).

Paquetages

En Java

Dans un diagramme de classes UML

On place toutes les classes d'un paquetage dans un rectangle nommé.

Classes internes

Quelques exemples

class A
{
	static class B
	{
	}
}

Nous pouvons instantier B en dehors de A : A.B b = new A.B();.

class A
{
	class B 
	{
		public A getSurroundingObject()
		{
			return A.this;
		}
	}
}

B n'est instantiable qu'à l'intérieur d'une méthode de A.

Classes anonymes et expressions lambdas

Un exemple calculant la surface d'un forme

Définissons l'interface Shape définissant une zone cible avec une méthode indiquant si un point s'y trouve :

Content not available

Nous réalisons une class mesurant l'aire de la cible en testant si des points placés aléatoirement s'y trouvent :

Content not available

Nous crééons une méthode main dans une classe AreaComputerTester pour tester notre classe :

Content not available