Design Concept Concept Concept Using J #

xiaoxiao2021-03-06  43

Release Date: 3/18/2005

| Update Date: 3/18/2005

Pratap Lakshmanmicrosoft Corporation

Applicable to: Microsoft Visual J # .Netvisual Studio .NET

Summary: This article examines design solutions that can be used in Microsoft Visual J # .NET. This is the first part of the article series (including three parts) of how to solve the problem through J #.

This page

Introduction Problem Simply Solution Explains the class as the type of interface as a type factory policy design practice

In "Are Toy Problems Useful" [1], when Knuth summarizes the practicality of the toy problem, the educational value of a problem depends primarily on the application of the thinking process in the process of solving this problem. The frequency is high, and the usefulness of the answer to the question is nothing to do.

In this article, we will introduce how to solve problems through J #. Although these issues may be similar to the toy problem, we hope that you can find what the thinking process for solving these issues is helpful. These issues are simple enough and therefore do not cover the corresponding solution. The solution does not use any programming skills, and if you select the design obtained with different language, you can reuse these designs.

The other two parts in this article are the second part Delegates In Action With J # and the third part Solving Constraints with J #.

If you have specific questions or feedback, send us an email through jsfeedbk@microsoft.com. We look forward to your feedback.

Introduction

"Design" is driven by context. For products, this context refers to its use, its survival, materials, time factors, mode of use, and the like. The design of single aircraft is not suitable for aerospace planes. The design of the motor boat is not suitable for the aircraft carrier.

Software system design is not different. We must consider various problems, such as (only examples only):

performance

portability

What algorithms and data structures are used?

Control interaction between various parts

In view of this, good design usually has the following characteristics:

Description appropriate decomposition process

Modularity

Low coupling

flexible

Tape

We must consider the implementation when designing design.

We will use an example problem and try to explain the above problems.

This tutorial builds an example on a plurality of complete solutions, and improves it through the simple mode [2] in each step; in this process, we will explain the interface as a type " , "Factory", "strategy" and other modes.

Back to top

problem

Generating players may be used to play the six-sided dice of the game.

Back to top

Simple solution

Our purpose is not to win in any programming competition! All the work we need to do is to generate a simple six-sided dice.

We describe the dice as follows:

Dice is something that players can "throw". The value of the dice (on top) is the result of this "throw" operation.

That is, we describe the dice in full accordance with the operation we can perform ("throw").

We implemented this solution in App.jsl.

Listing 1.

// file: app.jsl

Public Class APP

{

Public static int roll ()

{

Java.util.random r = new java.util.random ();

Return (1 R.NextINT (6));

}

Public static void main (string [] args)

{

// roll multiple times

For (int i = 0; i <10; i )

{

System.out.println (roll ());

}

}

Back to top

Use the class as the type

Our last solution is not able to solve some problems:

We did not get the impression of using the dice.

What if we need to be ten dice? What code do we need to modify?

What if we need more than one dice? What code do we need to modify?

The code has a "magic" number (1, 6).

What is the relationship between roll () and dice? Is it captured in our program? Or is it existing in the programmer's mind?

What is the relationship between roll () and the number of faces on the dice?

We need to better express the dice.

We describe the dice as follows:

The dice is a thing.

Dice is something that players can "throw".

"Throw" operation can throw a dice.

The value of the dice (on top) is the result of this "throw" operation.

In addition, let us eliminate the limit of the number of faces that can have the dice. We will parameterize it.

This dice is implemented in Dice.jsl.

The dice is used in the application app.jsl.

Listing 2.

// file: dice.jsl

// this represents a die

Public Class Dice

{

Public Dice (INT i)

{

Numsides = i;

}

Public int SIDES ()

{

Return Numside;

}

// Number of Sides on the Die

Private int Numside;

}

// file: app.jsl

Public Class APP

{

Public Static Int Roll (Dice D)

{

Java.util.random r = new java.util.random ();

Return (1 R.NextINT (D.SIDES ()));

}

Public static void main (string [] args)

{

// Create a 6 Sided Die

Dice D1 = New Dice (6);

For (int i = 0; i <10; i )

{

System.out.println (ROLL (D1));

}

// Create An 8 Sided Die

Dice D2 = New Dice (8);

For (int i = 0; i <10; i )

{

System.out.println (ROLL (D2));

}

}

}

Back to top

Use the interface as a type

Recommoding module

Our previous solution allows us to have more than one dice.

Let us introduce the concept of client and server before continuing to discuss. Server provides a service. In this case, DICE.JSL provides a dice service. "Client" is app.jsl, which uses the service.

What is "coupling" between the client and the server? How close is the connection between the client and the dice used? What happens if we want to make some changes to the dice (for example, introducing some new data / methods)? Does the client need to recompile?

Is that reasonable? What if you use this dice in multiple files? What if it is used by multiple clients?

Use the interface as a type

We introduced a dice interface in rollable.jsl. The dice class in dice.js is implemented. Client app.jsl only works according to this interface.

Listing 3.

// file: rollable.jsl // an interface representing a die

Interface Rollable

{

Public int SIDES ();

}

// file: dice.jsl

// this represents the die; it now imports

// the Rollable Interface

Public Class Dice Implements ROLLABLE

{

Public Dice (INT i)

{

Numsides = i;

}

Public int SIDES ()

{

Return Numside;

}

// Number of Sides on the Die

Private int Numside;

}

// file: app.jsl

Public Class APP

{

Public Static Int Roll (Rollable D)

{

Java.util.random r = new java.util.random ();

Return (1 R.NextINT (D.SIDES ()));

}

Public static void main (string [] args)

{

// Create a 6 Sided Die

ROLLABLE D1 = New Dice (6);

For (int i = 0; i <10; i )

{

System.out.println (ROLL (D1));

}

// Create An 8 Sided Die

Rollable D2 = New Dice (8);

For (int i = 0; i <10; i )

{

System.out.println (ROLL (D2));

}

}

}

Have you seen other areas we can improve?

Back to top

factory

coupling

Our previous solution has caused problems associated with coupling between clients and servers.

Our design must support the independent evolution of the client and server.

Therefore, we need to reduce the coupling between them to the lowest level.

As is currently realized, the implementation of the dice is "visible" for the client. This means that when we change the dice class next time, the client needs to recompile. There is no significant separation between the client and the server.

Let us separate the client and the server significantly.

We created a new class - DiceFactory.jsl - manages the creation of the dice object. The client now only processes according to the plant. This also provides the server with the flexibility of managing the storage of dice. The client no longer needs to know the following information: Where is the scorpion? Is the dice allocated on a pile? Is the dice allocated from the pre-allocated "Dice" collection? and many more.

Now, the following files provide a dice service (assuming life is DICE.dll).

Dice.jsl

Rollable.jsl

DiceFactory.jsl

App.jsl is the client (reference DICE.dll).

The "actual" of the dice means that it is no longer (and no need) "visible" for the client. The coupling between the client and the server is limited to DiceFactory.jsl and interface rollable.jsl.

We have isolated the client with the server!

Listing 4.

// file: dice.jsl

// this represents a die

Public Class Dice Implements ROLLABLE

{

Public Dice (INT i)

{

Numsides = i;

}

Public int SIDES ()

{

Return Numside;

}

PRIVATE INT NUMSIDES;

// file: rollable.jsl

// the interface representing a die

Interface Rollable

{

Public int SIDES ();

}

// file: DiceFactory.jsl

// this class handles the creation of dice

Public Class DiceFactory

{

Public Static Rollable Create (INT i)

{

Rollable D = New Dice (i);

Return D;

}

}

// file: app.jsl

Public Class APP

{

Public Static Int Roll (Rollable D)

{

Java.util.random r = new java.util.random ();

Return (1 R.NextINT (D.SIDES ()));

}

Public static void main (string [] args)

{

// Creation of Dice is Done Through The Factory

// Create a 6 Sided Die

ROLLABLE D1 = DiceFactory.create (6);

For (int i = 0; i <10; i )

{

System.out.println (ROLL (D1));

}

// Create An 8 Sided Die

ROLLABLE D2 = DiceFactory.create (8);

For (int i = 0; i <10; i )

{

System.out.println (ROLL (D2));

}

}

}

Back to top

Strategy

flexibility

Keep in mind that we are using dice in the game program - gamble by people, or like in casinos.

No casino likes to lose. Therefore, one of the requirements is to make the throwing dice with predictable results. This is generally called "loading" dice. If the casino starts, they switched to the "loaded" dice. Then they can beat you and start making money.

Under normal circumstances, the dice has the loading of "randomness"; that is, the result will be the random number in the number ranges of the dice.

test

How do game developers test the game? If the result of the throwing is random, it is difficult to write test cases (although in this example, the results will be in the fixed range). We must ensure that the predictable results are obtained in order to effectively test our software.

Strategy

We must change the "loading" policy without re-generating our dice components. (We may even do not have corresponding source code!) Whether it is from flexibility or test perspectives, it is worthwhile to change the throw ("loading") dice at runtime.

solution

We abstract the dice in rollstrategy.jsl as an interface. Each dice is referenced by this interface to the instance of the RollStrategy object. We abstract "loading" an abstraction of a method on the dice interface, which allows us to set ROLLSTRATEGY to be used by the dice. This object indicates the policy to be used when the dice is used.

We enhance the dice in dice.jsl. We move the Roll method to App.jsl and create a randomroll class (randomroll.jsl) to indicate a random distribution policy. This is the default policy used by the dice.

We introduced a method for loading a dice in rollable.js, and implemented it in the dice dice dice.jsl. The ROLL function is now using this "loading" to perform a roll-in operation. We updated DiceFactory.jsl to set the default load of the dice when you created. We created a Cyclicroll policy in a similar manner in Cyclicroll.jsl.

Now, the client will initialize the desired roll strategy, set the policy on the dice, then throw the dice. Please note how we change it at runtime.

Server files (assuming life is DICE.dll).

Dice.jsl, randomroll.jsl,

DiceFactory.jsl, Rollable.jsl, Rollstrategy.jsl

Listing 5.

// file: dice.jsl

// this represents a die.

// Note That it can be 'loaded' with a rolling statate

Public Class Dice Implements ROLLABLE

{

Public int SIDES ()

{

Return Numside;

}

Public Dice (INT i)

{

Numsides = i;

LOAD = NULL;

}

Public Void Load (Rollstrategy R)

{

LOAD = R;

}

Public int roll ()

{

INT i = -1;

IF (Load! = NULL)

{

i = loading.roll ();

}

Return I;

}

Private int Numside;

PRIVATE ROLLSTRATEGY LOAD;

}

// file: randomroll.jsl

// this represents on Strategy of Loading a Die

Public Class Randomroll IMPLEments ROLLSTRATEGY

{

Public Randomroll (INT I, INT J)

{

From = i;

THROUGH = J;

}

Public int roll ()

{

Java.util.random r = new java.util.random ();

INT CEILING = THROUGH 1;

INT i = from r.nextint (ceiling);

Return I;

}

Private int from;

PRIVATE INT THROUGH;

}

// file: DiceFactory.jsl

// this class handles the creation of dice

// it loads the Die with a rolling strategy as

// Part of the initialization of a die

Public Class DiceFactory

{

Public Static Rollable Create (INT i)

{

Rollable D = New Dice (i);

Rollstrategy r = new randomroll (1, i);

D.LOAD (R);

Return D;

}

}

// file: rollable.jsl

// the interface representing a die

Interface Rollable

{

Public int SIDES ();

Public Void Load (Rollstrategy R);

Public int roll ();

}

// file: rollstrategy.jsl // the interface That Repesents a rolling strategy

Interface rollstrategy

{

Public int roll ();

}

Client files (reference DICE.dll).

App.jsl, cyclicroll.jsl

Listing 6.

// file: app.jsl

Public Class APP

{

Public Static Int Roll (Rollable D)

{

INT i = D. roll ();

Return I;

}

Public static void main (string [] args)

{

// Create a die; by DeaFult it is loadinged with

// the random rolling strategy

Rollable D = DiceFactory.create (6);

For (int i = 0; i <10; i )

{

System.out.println (roll (d));

}

// Explicitly Load It with a differentent

// rolling strategy at 'Run Time'

RollStrategy R = New Cyclicroll (1, D.SIDES ());

D.LOAD (R);

For (int i = 0; i <10; i )

{

System.out.println (roll (d));

}

}

}

// file: cyclicroll.jsl

// this represents One Strategy of Loading a Die

Public Class Cyclicroll IMPLEments ROLLSTRATEGY

{

Public Cyclicroll (Int i, int J)

{

From = i;

THROUGH = J;

Curval = from;

}

Public int roll ()

{

IF (Curval> Through)

{

Curval = from;

}

RETURN CURVAL ;

}

Private int curval;

Private int from;

PRIVATE INT THROUGH;

}

Only DiceFactory.jsl, Rollable.jsl, RollStrategy.jsl is "visible" for the client.

This implementation has the following characteristics:

Obviously separation between clients and servers

Modularity

Low counted (limited to interface level)

Support the independent evolution of clients and servers

We can change the strategy of the arrest at runtime (flexibility)

Support test

complete.

This completes our "Dice Design" project.

I hope you can learn some knowledge during this process!

Back to top

Design exercise

Unlike a single dice supporting multiple loading strategies, we can have a dice hierarchy, each of which supports different strategies. Please contact our best to discuss the advantages of this.

Unlike let the dice implement the Rollable interface, we can have an abstract class that represents the dice, and all the specific implementations of the dice are inherited from the abstraction class. Please contact our best to discuss the advantages of this.

Extend the dice to allow you to have different types of objects on each face. For example, the scorpion can have a letter, and it is also possible to have a picture.

reference

[1] Knuth, Donald, E., SELECTED PAPERS on Computer Science, Cambridge University Press, 1996 [2] Design Patterns: Elements of Reusable Object-Oriented Software "Gamma E. et al. Addison Wesley, 1995

Go to the original English page

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

New Post(0)