Translation Tipatterns - Encapsulating Creation

xiaoxiao2021-03-06  191

Encapsulating Creation

When you find that you need to add some new types to a system, the most sensible approach is to create a public interface for these new types with Polymorphism. This allows the code of the rest of the system to be separated from those of the newly added specific types. Adding new types may not change existing code. . . Or at least it looks unnecessary. It seems that if you modify the code with this design method mentioned above, the only thing that needs to be changed is to inherit the new type, but in fact is not exactly the case. You still need to create new types of objects, and where you must specify which constructor is used. Therefore, if the part of the code used to create an object is dispersed throughout the program (you will face this problem when adding a new type), you still need to find all the code related to the type. In this case, the main problem is the creation of the new type (object) rather than the new type of use (this problem can be solved by polymorphism), but the actual effect is the same: adding a new type will always bring problems. The solution is to force a COMMON FACTORY to create an object without allowing code to create an object to be dispersed throughout the system. If all those who need to create objects are created with this factory (Factory), then you need to do it when you add new types. It is possible to modify this factory. Because all object-oriented code will be used to create objects, and in most cases you will extend programs by adding new types, I guess the Factory mode (series) may be the most widely used design mode. Although only Simple Factory Method is a single piece (Singleton), you will find that every specific factory class (these classes belong to more common Factory mode) actually only one instance.

Simple factory method (Simple Factory Method)

We take a revolution with the following examples. (Implementing Factory mode) Commonly used method is to declare the Factory as a static method of the base class (STATIC METHOD).

//: Factory: ShapeFact1: ShapeFactory1.java

// a Simple Static Factory Method.

Package factory.shapefact1;

Import java.util. *;

Import junit.framework. *;

Abstract class shape {

Public Abstract void Draw ();

Public abstract void erases;

Public Static Shape Factory (String Type) {

IF (Type.equals ("Circle")) Return New Circle ();

IF (Type.equals ("Square")) Return New Square ();

Throw new runtimeException

"Bad Shape Creation:" TYPE);

}

}

Class Circle Extends Shape {

Circle () {} // package-access constructor

Public void draw () {

System.out.println ("Circle.Draw");

}

Public void erase () {

System.out.println ("Circle.ed");

}

Class Square Extends Shape {

Square () {} // package-access constructor

Public void draw () {

System.out.println ("Square.Draw");

}

Public void erase () {

System.out.println ("Square.rase");

}

}

Public class shapefactory1 extends testcase {

String shlist [] = {"circle", "Square",

"Square", "Circle", "Circle", "Square"};

List shapes = new arraylist ();

Public void test () {

Iterator it = arrays.aslist (shlist) .Itemrator ();

While (it.hasnext ())

Shapes.add (Shape.Factory ((String) IT.NEXT ());

IT = shapes.iterator ();

While (it.hasnext ()) {

Shape s = (shape) it.next ();

s.draw ();

S.RASE ();

}

}

Public static void main (string args []) {

JUnit.textui.testrunner.run (ShapeFactory1.class);

}

} ///: ~

The factory () method needs to pass a parameter to determine the specific type of Shape to create; in the above example (parameter), it can be a string, which can also be any other type. When adding a new Shape type (we assume that the initialization code of the object is from the system, instead of using a hard-coded array), the only code that needs to be changed is Factory. ()method. In order to cause the code to create an object, only in the factory () method, the constructor of a particular type of Shape class is declared as package permission, so that only the factory () method can call these constructors, and is located (package) The part of the code outside does not have enough permissions (call these constructor).

In the Polymorphic Factories, static factory () methods make all the operations of all creating objects are set in one place, which is the only place where you need to modify the code. This is of course a good solution, which encapsulates the process of creating an object. However, "design mode" emphasizes that using Factory Method is to make different types of factories can be derived from basic types (Subclass). However, the book did not give a specific example, just repeated the example used to explain Abstract Factory (you will see an example of an Abstract Factory in this book). The following example, we modified ShapeFactory1.java to make the factory method a virtual function of a separate class. Please note that a specific type of Shape class is dynamically loaded as needed. //: Factory: Shapefact2: ShapeFactory2.java

// Polymorphic Factory Methods.

Package factory.shapefact2;

Import java.util. *;

Import junit.framework. *;

Interface shape {

Void Draw ();

void erases;

}

Abstract class shapefactory {

Protected abstract shape create ();

Private static map factories = new hashmap ();

Public static void

AddFactory (String ID, ShapeFactory f) {

Factories.put (ID, f);

}

// a Template Method:

Public Static Final

Shape createShape (String ID) {

IF (! Factories.Containskey (ID)) {

Try {

// load dynamically

Class.Forname ("Factory.ShapeFact2." ID);

} catch (classnotfoundexception e) {

Throw new runtimeException

"Bad Shape Creation:" ID);

}

// See if it is put in:

IF (! Factories.ContainsKey (ID))

Throw new runtimeException

"Bad Shape Creation:" ID);

}

Return

(ShapeFactory) Factories.get (ID)). CREATE ();

}

}

Class Circle Implements Shape {

private circle () {}

Public void draw () {

System.out.println ("Circle.Draw");

}

Public void erase () {

System.out.println ("Circle.ed");

}

Private static class factory

Extends shapefactory {

Protected Shape Create () {

Return new circle ();

}

}

STATIC {

ShapeFactory.AddFactory (

"Circle", new factory ());

}

Class Square Implements Shape {

Private square () {}

Public void draw () {

System.out.println ("Square.Draw");

}

Public void erase () {

System.out.println ("Square.rase");

}

Private static class factory

Extends shapefactory {

Protected Shape Create () {

Return new Square ();

}

}

STATIC {

ShapeFactory.AddFactory (

"Square", new factory ());

}

}

Public Class ShapeFactory2 Extends Testcase {

String shlist [] = {"circle", "Square",

"Square", "Circle", "Circle", "Square"};

List shapes = new arraylist ();

Public void test () {

// this Just Makes Sure IT Will Complete

// WITHOUT THROWING AN Exception.

Iterator it = arrays.aslist (shlist) .Itemrator ();

While (it.hasnext ())

Shapes.add

ShapeFactory.createshape (String) IT.Next ()));

IT = shapes.iterator ();

While (it.hasnext ()) {

Shape s = (shape) it.next ();

s.draw ();

S.RASE ();

}

}

Public static void main (string args []) {

JUnit.textui.teStrunner.run (ShapeFactory2.class);

}

} ///: ~

Now the factory method appears in its own class ShapeFactory, the name is changed to the create () method. It is a protected method, that is, it cannot be called directly, but can be overloaded. Subclas for the Shape class must create subclasses of the corresponding ShapeFactory and create its own instance by overloading the create () function. In fact, the creation of a series of Shape objects is done by calling ShapeFactory. CreateShape (). CreateShape () is a static method that found the corresponding factory object (Factory Obejct) based on the incoming markup. Then, find the Factory object is used to create a Shape object, but you can imagine a more tricky question: (corresponding to some Shape type) factory object is used to create objects in more complicated manner . However, in most cases, you don't do not need to use a complicated polymorphic factory method, add a static method in the base class (like ShapeFactory1.java) is enough to solve the problem. Note that the initialization of ShapeFactory must be completed by loading the MAP data (the element of the MAP is a Factory object), and these initialization code is also in the static initialization statement of the Shape implementation class. In this way, every new type you must have to inherit the original type (refer to Shape?), Create a Factory, then add a static initialization statement to load the MAP object. These additional complexities have again suggest us: If you don't need to create a separate Factory object, it is best to use a static factory method. Abstract Factory Abstract Factory The pattern looks like the Factory object we see in front, but it has multiple rather than a Factory method. Each Factory method creates a different type of object. Basic ideas are: In the place where the factory object is created, you will determine how the objects created using the factory object. The example given in "Design Mode" implements portability between different user graphics interfaces (Guis): You create a corresponding Factory object based on your own GUI, after this, when you need to use When you go to the menu, buttons, scroll these things, it automatically creates the appropriate object based on the GUI you use. In this way, you can separate the code to switch between different GUIs to make it concentrated in one place.

As another example, assume you create a universal gaming environment and you still want to support different types of games. The following example gives a possible implementation with an abstract factory.

//: Factory: Games.java

// an Example of the Abstract Factory Pattern.

Package factory;

Import junit.framework. *;

Interface Obstacle {

Void Action ();

}

Interface Player {

Void InteractWith (OBSTACLE O);

}

Class Kitty Implements Player {

Public void interactwith (obstacle ob) {system.out.print ("Kitty Has Encountered A");

ob. activity ();

}

}

Class Kungfuguy Implements Player {

Public void interactwith (Obstacle ob) {

System.out.print ("Kungfuguy Now Battles A);

ob. activity ();

}

}

Class Puzzle IMPLEments OBSTACLE {

Public void action () {

System.out.println ("puzzle");

}

}

Class Nastyweapon Implements Obstacle {

Public void action () {

System.out.println ("NastyWeapon");

}

}

// The Abstract Factory:

Interface GameElementFactory {

Player makeplayer ();

Obstacle makeobstacle ();

}

// Concrete Factories:

Class Kittiesandpuzzles

Implements GameElementFactory {

Public Player makeplayer () {

Return new kitty ();

}

Public Obstacle makeobstacle () {

Return new puzzle ();

}

}

Class KillandDismember

Implements GameElementFactory {

Public Player makeplayer () {

Return new kungfuguy ();

}

Public Obstacle makeobstacle () {

Return new NastyWeapon ();

}

}

Class GameEnvironment {

PRIVATE GAMEEEEMENTFACTORY GEF;

Private Player P;

Private Obstacle OB;

Public GameEnvironment

GameElementFactory Factory) {

GEF = Factory;

P = factory.makeplayer ();

Ob = factory.makeobstacle ();

}

Public void play () {p.interactwith (ob);

}

Public Class Games Extends Testcase {

GameElementFactory

KP = new kittiesandpuzzles (),

Kd = new killanddismember ();

GameEnvironment

G1 = New GameEnvironment (KP),

G2 = New GameEnvironment (kd);

// Thase Just Ensure No Exceptions Are Thrown:

Public void test1 () {g1.play ();

Public void test2 () {g2.play ();

Public static void main (string args []) {

Junit.textui.teStrunner.Run (Games.class);

}

} ///: ~

In the above gaming environment, the Player object interacts with the Obstale object, depending on the type of game you selected, the Types of Player and Obstacle will be different. You determine the type of game by selecting a specific GameElementFactory, then GameElementFactory will control the initialization and game progression. In the above example, the initialization and games are very simple, but those activities (initial conditions and status changes) can greatly determine the ending of the game. Here, GameEnvironment is not used to inherit other classes, although it is likely to say. The above code also includes two modes of Double Dispatching and Factory Method, we will explain them later. Exercise: 1. Write a Triangle class, add to ShapeFactory1.java. 2. Write a Triangle class, add to ShapeFactory2.java. 3. Add a new type to GameEnvironment, write a gnomesandfairies added to Games.java. 4. Cover ShapeFactory2.java, create Shapes of different specifications (for example, with a specific type of factory object to create "Thin Shapes" with another factory object, but each Factory objects can create all types of Shapes, including: Circles, Squares, Triangles, etc.).

table of Contents

转载请注明原文地址:https://www.9cbs.com/read-128786.html

New Post(0)