Вызовите шаблон "одиночка" в подклассах

это работает .. вы допустили две небольшие ошибки, которые я прокомментировал внутри кода нужно обернуть содержимое цикла внутри {}. и пользовательский ввод должен быть возвращен в виде строки в функции askUser. следующий код работает так, как вы хотели.

package javaapplication1;
  import java.util.*;




public class JavaApplication1 {

private int points;
    private int limit;
   private Scanner scan;

    public JavaApplication1(){
        scan = new Scanner(System.in);


    }

    public void displayPoints(){
        System.out.println("Your points:" + points+"/"+limit);
   }
   /*Purpose: To ask the user for the game limit.
      Input: Game limit
      Output: Entered limit
    */
   public void startGame(){
        System.out.println("Enter point limit:");
        limit = scan.nextInt();
        displayPoints();
   }

   public int getRoll(){
        Random r = new Random();
        int roll = r.nextInt(6)+1;
        System.out.println("You rolled:" + roll);
       return roll;
    }   

    public String askUser(boolean firstTime){

        if(firstTime == true)
        System.out.println("Start Playing?");

        else {
        System.out.println("Keep playing?");

      }

        return scan.next();
    }

    public void displayResult(){
        if(points == limit)
            System.out.println("BlackJack!");
        else if (points > limit)
            System.out.println("Bust!");
        else if (points < limit)
            System.out.println("Stand at " + points + " points!");  
    }



    public void play(){


        boolean gameOver = false;
        startGame();
        String resUser = askUser(true); // add a variable to catch the input //exp-"yes"
        String response = "";
        int roll = getRoll();

        while(resUser.equals("yes")&& gameOver == false){ // you forget the { and use //the variable to check if it is yess or not 
            getRoll();
            points = points + roll;
            displayPoints();


            if(points >= limit)
            gameOver =true;

            else{

            resUser = askUser(false);//catching the new user input 


            }

        }// you forget the }. if you are not wrapping the loop with {}, it will only //execute one line after the loop 

        displayResult();
    }

    public static void main(String [] args){
    JavaApplication1 practice = new JavaApplication1();

    practice.play();


    }



}
8
задан Ben S 27 February 2009 в 16:59
поделиться

5 ответов

Пересмотрите. Вы НЕ хотите использовать одиночные элементы здесь. Вы делаете некоторую функциональность доступной для пользователей, которые происходят из Вашего класса. Это прекрасно. Но Вы также диктуете один особенный метод, в котором это должно всегда использоваться, и по абсолютно никакой причине. Это не хорошо.

Может иметь смысл только инстанцировать одного объекта этого класса большинство времени, но в этом случае, просто просто инстанцировать объекта однажды. Это не похоже, Вы, очень вероятно, случайно инстанцируете дюжины объектов без того, чтобы замечать. Кроме того, как можно сказать, что наличие двух экземпляров никогда не будет полезно? Я могу думать о нескольких случаях даже сейчас.

Поблочное тестирование: Вы могли бы хотеть, чтобы каждый тест инстанцировал этого объекта и разъединил его снова впоследствии. И так как у большинства людей есть больше чем один модульный тест, необходимо будет инстанцировать его несколько раз.

Или Вы могли бы в какой-то момент решить иметь несколько идентичных/подобных уровней в своей игре, что означает создавать несколько экземпляров.

Одиночный элемент дает Вам две вещи:

  • Гарантия, что не больше, чем один экземпляр объекта будут когда-либо инстанцировать, и
  • Глобальный доступ к тому экземпляру

Если Вам не нужны обе этих вещи, существуют лучшие альтернативы. Вам, конечно, не нужен глобальный доступ. (globals плохи, и обычно признак плохого дизайна, особенно в изменяемых данных, таких как Ваше игровое состояние),

Но Вам не нужна гарантия, что не больше, чем экземпляры будут когда-либо инстанцировать также. Действительно ли это - конец света, если я инстанцирую объекта дважды? Будет сбой приложения? Если так, Вам нужна та гарантия. Но в Вашем случае, ничего плохо не произойдет. Человек, инстанцирующий объекта просто, использует больше памяти, чем необходимый. Но у него могла бы быть причина.

Просто вставьте документацию класса, что это - очень большой и дорогой класс, и Вы не должны инстанцировать ее чаще, чем необходимый. Проблема решена. Вы не удаляете гибкость, которая могла бы оказаться полезной позже, Вы не предоставляете глобальный доступ к данным ни по какой причине. Поскольку можно управлять, кто видит объект, Вы не должны топить его в блокировках, которые станут узким местом в многопоточных приложениях. У Вас нет скрытых зависимостей рассеянными всюду по Вашему коду, мешая тестировать и тяжелее к повторному использованию.

7
ответ дан 5 December 2019 в 14:06
поделиться

Попытайтесь использовать контейнер МОК. Самые хорошие контейнеры МОК включают использование шаблона "одиночка", не имея необходимость реализовывать его самостоятельно (т.е.: пружинная платформа) - мне нравится это лучше, чем принуждение статического GetInstance () метод.

Кроме того, это не действительно возможно в Java, это работало бы в C++ с шаблонами все же.

4
ответ дан 5 December 2019 в 14:06
поделиться

Почему? Если кто-то хочет использовать несколько экземпляров подкласса Вашего класса, у них могла бы быть совершенно допустимая причина для.

Если Вы хотите сделать что-то, что только должно быть сделано однажды для каждого класса, который разделяет Ваш класс на подклассы (почему, я понятия не имею, но у Вас могла бы быть причина для), используйте Словарь в базовом классе.

1
ответ дан 5 December 2019 в 14:06
поделиться

Я думаю, что Вы будете более обеспечены с шаблоном "фабрика" здесь, чтобы быть честными. Или используйте инструмент IoC как Brian Dilley, рекомендует. В c# мире существуют загрузки, здесь являются самыми популярными: замок/Виндзор, StructureMap, Единица, Ninject.

То, что в стороне, я думал, что это будет забава делать попытку фактического решения Вашей проблемы! Взгляните на это:

//abstract, no one can create me
public abstract class Room
{
    protected static List<Room> createdRooms = new List<Room>();
    private static List<Type> createdTypes = new List<Type>();

    //bass class ctor will throw an exception if the type is already created
    protected Room(Type RoomCreated)
    {
        //confirm this type has not been created already
        if (createdTypes.Exists(x => x == RoomCreated))
            throw new Exception("Can't create another type of " + RoomCreated.Name);
        createdTypes.Add(RoomCreated);
    }

    //returns a room if a room of its type is already created
    protected static T GetAlreadyCreatedRoom<T>() where T : Room
    {
        return createdRooms.Find(x => x.GetType() == typeof (T)) as T;
    }
}

public class WickedRoom : Room
{
    //private ctor, no-one can create me, but me!
    private WickedRoom()
        : base(typeof(WickedRoom)) //forced to call down to the abstract ctor
    {

    }

    public static WickedRoom GetWickedRoom()
    {
        WickedRoom result = GetAlreadyCreatedRoom<WickedRoom>();

        if (result == null)
        {
            //create a room, and store
            result = new WickedRoom();
            createdRooms.Add(result);
        }

        return result;
    }
}

public class NaughtyRoom :Room
{
    //allows direct creation but forced to call down anyway
    public NaughtyRoom() : base(typeof(NaughtyRoom))
    {

    }
}

internal class Program
{
    private static void Main(string[] args)
    {
        //Can't do this as wont compile
        //WickedRoom room = new WickedRoom();

        //have to use the factory method:
        WickedRoom room1 = WickedRoom.GetWickedRoom();
        WickedRoom room2 = WickedRoom.GetWickedRoom();

        //actually the same room
        Debug.Assert(room1 == room2);

        NaughtyRoom room3 = new NaughtyRoom(); //Allowed, just this once!
        NaughtyRoom room4 = new NaughtyRoom(); //exception, can't create another
    }
}

WickedRoom является классом, который правильно реализует систему. Любой клиентский код овладеет одиночным элементом класс WickedRoom. NaughtyRoom не реализует систему правильно, но даже этот класс нельзя инстанцировать дважды. 2-е инстанцирование приводит к исключению.

0
ответ дан 5 December 2019 в 14:06
поделиться

Я определил бы запечатанный класс, который добирается, его функциональность от делегатов передала конструктору, чему-то вроде этого:

public sealed class Shape {
  private readonly Func<int> areaFunction;

  public Shape(Func<int> areaFunction) { this.areaFunction = areaFunction; }

  public int Area { get { return areaFunction(); } }
}

Этот пример не имеет большой смысл, он просто иллюстрирует шаблон. Такой шаблон не может использоваться везде, но иногда он помогает.

Кроме того, это может быть расширено для представления конечного числа статических полей:

public sealed class Shape {
  private readonly Func<int> areaFunction;

  private Shape(Func<int> areaFunction) { this.areaFunction = areaFunction; }

  public int Area { get { return areaFunction(); } }

  public static readonly Shape Rectangle = new Shape(() => 2 * 3);
  public static readonly Shape Circle = new Shape(() => Math.Pi * 3 * 3);
}
0
ответ дан 5 December 2019 в 14:06
поделиться
Другие вопросы по тегам:

Похожие вопросы: