2014년 2월 10일 월요일

[Java] parameter에 "변수명 = 값"을 넣으면?

원래 parameter에 "변수명 = 값"이라고 넣은 건
parameter에 값을 전달하고 해당 변수명에 값을 할당하려는 시도였다.

시도했던 코드 : 
while(reader.ready() && !data[0].equals(line = username + "\t" + password
                    + "\t" + phoneNumber + "\t" + String.valueOf(reservedOrNot))){
                readLine = reader.readLine();
                data = readLine.split(";");
            }

굵은 글씨 부분이다.

그런데 java 문법에 어긋난 행위다. 에러남

???????????


package classchum;

public class Test1212 {
public static void main(String argv[]){
int a, b;
a = test(b=2, 1);
System.out.println(a);
System.out.println(b);
}

static public int test(int a, int b){
return b;
}
}

결과:
1
2

2014년 1월 15일 수요일

간단하게 Activity stack 처리하는 방법 (Android)

Activity를 그냥 intent생성해서 만들면 계속해서 새로 Activity를 start하고 스택으로 쌓이는 문제가 발생한다.
예를 들어서 A, B, C Activity를 A->B->C->A->C->B로 이동하고 뒤로가기를 누르면 다시 화면이 B->C->A->C->B->A 순으로 왔던 순서 반대로 나타난다. 그래서 뜨면 안될 화면도 뜨게 된다. (*회원가입 화면이 그대로 다시뜬다던가 삭제한 화면이 뜬다던가 등) 혹은 그냥 다시 뒤로가면 되는 화면인데 새로운 화면을 만들어서 그 위에 쌓아나간다.

여기서 생기는 두가지 문제,
1. 접근해선 안되는 이전화면으로 돌아가버린다.
2. 굳이 이전 화면의 Activity를 새로 생성해서 위에 쌓는다.

를 해결해보자.


1. 접근해선 안되는 이전화면으로 돌아가버리는 문제

->해당 Activity 의 JAVA 소스 파일에서 intent를 생성한 바로 다음에
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
를 추가해준다.

여기서 FLAG_ACTIIVTY_CLEAR_TASK는 기존에 쌓여있던 task(stack이 모여 형성하는 작업의 단위(?))를 모두 삭제하는 조건(?)을 받는 flag 상수다. Intent 클래스에 statitc final로 선언되어있다.

즉 intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK); 는 기존에 쌓여있던 스택을 모두 없앤다.

이때 FLAG_ACTIVITY_NEW_TASK로 task를 새로 생성한다. 이때 root activity는 intent가 새로 생성한 activity가 된다.


2. 이전 화면의 Activity로 돌아가야하는 문제

-> 돌아가기 이전 Activity의 JAVA 소스 파일에서 intent를 생성한뒤에
intent.addFlags(intent.FLAG_ACTIVITY_CLEAR_TOP);
을 추가해준다.

FLAG_ACTIVITY_CLEAR_TOP 은 이전 Activity를 새로운 Activity로 지정하고 현재 Activity는 Clear하는 flag상수다. 역시 Intent 클래스에 static final로 선언되어 있다.

따라서, 현재 Activity를 없애고 이전 화면을 새로운 화면으로 지정하기 때문에 자연스럽게 이전화면으로 돌아간다.

** 2.번 문제는 Manifest파일에 android:launchmode="singleTop"을 추가해 주면 비슷하게 문제를 해결할 수 있다.
자세한건
http://developer.android.com/guide/components/tasks-and-back-stack.html
(tasks and back stack에 대한 android document)
참조.


2014년 1월 13일 월요일

Singleton = 특정클래스의 인스턴스를 하나만 생성하는 방법

특정 클래스의 인스턴스를 하나만 생성해야 하는 경우가 있다.

왜 그런상황이 생기는지 회원가입, 로그인을 예로 들어보자.
회원DB 클래스의 인스턴스를 회원가입과 로그인에서 
각각 A인스턴스, B인스턴스로 따로 생성하였다. 이때 회원 이모씨가 서비스에 가입하였다. 이모씨의 회원가입은 A인스턴스가 실행하였다. 그런데 이모씨는 제대로 로그인이 되는지 확인하기 위해 잠깐 로그아웃을 하고 다시 로그인을 시도하였다. 그런데 이때 사용된 B인스턴스에는 이모씨의 정보가 추가되어 있지 않다. 이모씨는 로그인에 실패하여 어플을 지워버렸다.
이 상황에서 B인스턴스 입장에서는 A인스턴스를 통해서 회원가입이 일어났는지 확인할 길이 없다. 한 클래스에서 여러 인스턴스를 생성하면서 발생하는 문제다.

이 경우 반드시 하나의 인스턴스만을 생성하여 해당 인스턴스를 하상 호출하여 사용하도록 하면 문제가 해결된다. 

이때 사용되는 하나의 인스턴스만을 사용하도록 하는 '디자인 패턴'을 Singleton이라고 한다.


Singleton은 
1. 클래스 내에 인스턴스를 생성하고

2. 생성자를 private으로 선언하여 
외부에서 해당 인스턴스를 생성하지 못하도록 한다.

3. 외부에서 해당 인스턴스를 사용하려고 할 경우 getInstance()를 이용하여 
클래스 내에 이미 선언된 인스턴스만을 사용하도록 한다.

고로 해당 클래스 내에서 static으로 생성된 인스턴스만 사용되는 것이다.
프로그램내의 모든 곳에서 해당 클래스의 특성 인스턴스만 사용한다.


간단한 코드 예시

public class MemberManager {
1.   private static MemberManager instance = null;
    

2.   private MemberManager() {
        this.members = this.getMembersFromFile();
    }
3.   public static MemberManager getInstance() {
// 아직 인스턴스가 생성되지 않았을 경우 최초 생성한다.
        if(MemberManager.instance == null)
            MemberManager.instance = new MemberManager();
        return MemberManager.instance;
    }
}



+추가
private static MemberManager instance로 선언하는 이유가 뭐냐.
그냥 private으로 선언하면 어떻게 됨?

-> 3.에서 변수 instance를 사용하는데 (그냥 private이면)static이 아니므로
1) 객체를 생성하지 않고 사용하면 컴파일이 되지않는다.
2) 객체를 생성하면 해당 static 메소드를 호출할때마다 객체를 생성하기 때문에
하나의 특정 객체만을 생성하고 사용하는 싱글톤이 더이상 아니게 된다.

++추가 static 메소드, 변수는 왜 쓰는 건가요?
-> 클래스 자체에 관련해서 설명이 필요한 경우 사용한다.
ex) 사용자가 로그인을 할때마다 사용자 객체를 생성하는 클래스가 있다.
현재 사용중인 사용자 목록을 가져오는 메소드가 필요한 경우
static으로 선언하여 사용한다. 어떤 특정 객체에 연관되지 않고 사용할 메소드이기 때문.
물론 일반 메소드로 선언하여 사용할 수도 있으나, 특정 객체를 지정하여 메소드를 호출하여야 하고, 부자연스럽다.
결론 : static 메소드, 변수가 필요한 이유는 어느 객체에도 속하지 않는 행위, 데이터의 처리가 필요한 경우?

2014년 1월 7일 화요일

C언어 : structure를 활용한 파일처리(I/O)

클린코드 읽고 배운대로 함해봄.

목표 :
1) score.txt로부터 성적을 입력받아서, 학생 각각의 평균을 산출하고, 평균을 바탕으로 등수를 매긴다.
2) 이름, 성적, 평균, 등수를 콘솔에 출력한다.
3) 이름, 성적, 등수를 학생이름으로 된 txt파일에 출력한다.

--코드--
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

typedef struct report{
char* name;
int korean;
int math;
int english;
int number_of_students;
float average;
}REPORT;

int countStudents(FILE* fp_input);
void putInformation(FILE* fp_input, REPORT** reports_pointer, int number_of_students);
void calculateAndPutAverageOfEachStudentInReport(REPORT* reports);
void orderByScore(REPORT* reports);
void printChart(REPORT* reports);
void makeReportFiles(REPORT* reports);

int main()
{
FILE* fp_input;
REPORT* reports;
int number_of_students;
float* average;

fp_input = fopen("score.txt", "r");
if(fp_input == NULL){
fprintf(stderr, "File error!\n");
exit(1);
}

number_of_students = countStudents(fp_input);
rewind(fp_input);
putInformation(fp_input, &reports, number_of_students);
calculateAndPutAverageOfEachStudentInReport(reports);
orderByScore(reports);
printChart(reports);
makeReportFiles(reports);

return 0;
}

int countStudents(FILE* fp_input)
{
int number_of_students=0;
char string_for_count[20];
while(!feof(fp_input)){
fscanf(fp_input, "%s", string_for_count);
number_of_students++;
}
number_of_students /= 4;

return number_of_students;
}

void putInformation(FILE* fp_input, REPORT** reports_pointer, int number_of_students)
{
int i=0;

*reports_pointer = (REPORT*)malloc(sizeof(REPORT)*number_of_students);

while(!feof(fp_input)){
(*reports_pointer)[i].name = (char*)malloc(sizeof(char)*20);
fscanf(fp_input, "%s", (*reports_pointer)[i].name);
fscanf(fp_input, "%d", &(*reports_pointer)[i].korean);
fscanf(fp_input, "%d", &(*reports_pointer)[i].math);
fscanf(fp_input, "%d", &(*reports_pointer)[i].english);
(*reports_pointer)[i].number_of_students = number_of_students;
i++;
}
}

void calculateAndPutAverageOfEachStudentInReport(REPORT* reports)
{
int i=0;
for(i; i<reports[0].number_of_students; i++){
reports[i].average = (float)(reports[i].korean + reports[i].math + reports[i].english) / 3;
}
}

void orderByScore(REPORT* reports)
{
int i, j, temp_korean, temp_math, temp_english;
float temp_average;
char* temp_name;
for(i=0; i<reports[0].number_of_students-1; i++)
for(j=i+1; j<reports[0].number_of_students; j++){
if(reports[i].average < reports[j].average){
temp_average = reports[i].average;
reports[i].average = reports[j].average;
reports[j].average = temp_average;

temp_name = reports[i].name;
reports[i].name = reports[j].name;
reports[j].name = temp_name;

temp_korean = reports[i].korean;
reports[i].korean = reports[j].korean;
reports[j].korean = temp_korean;

temp_math = reports[i].math;
reports[i].math = reports[j].math;
reports[j].math = temp_math;

temp_english = reports[i].english;
reports[i].english = reports[j].english;
reports[j].english = temp_english;
}
}
}

void printChart(REPORT* reports)
{
int i;
printf("      이름        국어  수학  영어   평균     등수\n");
printf("-----------------------------------------------------\n");
for(i=0; i<reports[0].number_of_students; i++)
printf("%15s %5d %5d %5d %8.2f %6d\n", reports[i].name, reports[i].korean, reports[i].math, reports[i].english, reports[i].average, i+1);
}

void makeReportFiles(REPORT* reports)
{
int i;
FILE* fp_output;
for(i=0; i<reports[0].number_of_students; i++){
fp_output = fopen(strcat(reports[i].name, ".txt"), "w");
fprintf(fp_output, "이 름 : %s\n", reports[i].name);
fprintf(fp_output, "국어  : %d\n", reports[i].korean);
fprintf(fp_output, "수학  : %d\n", reports[i].math);
fprintf(fp_output, "영어  : %d\n", reports[i].english);
fprintf(fp_output, "등수  : %d\n", i+1);
}
}

아쉬운점:
* calculateAndPutAverageOfEachStudentInReport는 평균을 계산하는 작업과
평균 값을 각report structure에 넣는 작업 두가지를 한 함수에서 동시에 해결하고 있다.
** 각각의 함수는 출력 인수를 사용하고 있다.

여튼 그래도 ㅈㄴ 뿌듯 ㅎ

2013년 11월 30일 토요일

파이썬 자습서(한글판)

파이썬 원문 번역 사이트.. 이렇게 고마울데가

http://coreapython.hosting.paran.com/howto/tut/tut.html

Tutorial part 3 : Django 프로젝터 폴터, 루트(기본설정) 폴더

mysite라는 프로젝트 폴더안에는
polls와 mysite라는 폴더가 있다.
여기서 polls안에 urls.py를 만들고
mysite안에 또 urls.py를 만들럤는데 (doc.djangoproject.com 의 tutorial part3 참고)
만들었더니 뭔가 문제가 생김.

1차 문제 : 서버를 안켰음 ㅋㅋㅋㅋ

2차 문제 : mysite 폴더가 두개였음.. mysite 폴더가 Project폴더가 있고 root폴더가 있는데
root폴더에 만들어야 된다. 그래야 설정이 바뀌지.


오늘의 교훈 : 
Project 폴더명과 root폴더 명은 같다 (보통그렇다.)
Project 폴더 안에 root폴더가 있다.



Use the template system.
질문 : detail.html template가 왜 실행안되고 html404 오류페이지가 뜨는가?

2013년 11월 23일 토요일

JAVA AWT 공이 튀기고 사라지고 둘로쪼개지고

도전과제 : 
0. start버튼과 close버튼을 생성한다.
1. awt window frame 중간에 공 다섯개 만들어서 start버튼을 누를 경우 각기 다른 방향으로 가게 만든다.
2. 공이 부딪칠 경우 부딪친 상대 공의 움직임에 영향을 받아 이후 이동방향이 결정된다.
3. 부딪친 이후 이동방향의 좌우 45도로 공이 두개 새로 생성된다.
4. 부딪친 기존의 공은 부딪침과 동시에 사라진다.
5. 공이 부딪치기 전에 공의 반지름이 1px일 경우 공이 사라진다.

그렇다 이런 프로그램을 만든다.
아래는 코드

import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.util.ArrayList;
import java.math.*;

public class Homework_3 {
public static void main(String[] args)
{
MainFrame mainFrame = new MainFrame();
}
}

class MainFrame extends Frame
{
public static Canvas canvas;
public MainFrame()
{
/*프로그램 시작시 보여질 메인 프레임을 만든다.*/
this.setSize(400, 300);
canvas = new Canvas();
this.add("Center", canvas);
Panel p = new Panel();
Button s = new Button("Start");
Button c = new Button("Close");
s.addActionListener(new StartBtnClickListener());
c.addActionListener(new CloseBtnClickListener());
p.add(s);
p.add(c);
this.add("South", p);
this.addWindowListener(new WindowAdapter(){
public void WindowClosing(WindowEvent we){
System.exit(0);
}
});
this.setVisible(true);
}
}

class StartBtnClickListener implements ActionListener{
// Start 버튼을 눌렀을 때, 공튀기기 시작한다.
public void actionPerformed(ActionEvent evt){
// 공 5개를 생성해서 각각 다른방향으로 이동시키게 만든다.
for(int i=0; i<5; i++){
BallManager.balls.add(new Ball(200, 150, 20, i*(Math.PI/5)));
BallManager.balls.get(i).start();
}
}
}

class CloseBtnClickListener implements ActionListener{
// Close 버튼을 눌렀을때 프로그램을 종료한다.
public void actionPerformed(ActionEvent evt){
System.exit(0);
}
}

class Ball extends Thread
{
int diameter;
double radian;
int x, y;
double dx = 2, dy;
Canvas canvas = MainFrame.canvas;
boolean isRunnable = true;
//원을 만들때 x,y 좌표, 지름, 이동방향(각도)를 초기화한다.
public Ball(int x, int y, int diameter, double radian){
this.x = x;
this.y = y;
this.diameter = diameter;
this.radian = radian;
this.dy = dx*Math.tan(this.radian);
if(this.radian>=Math.PI/2 && this.radian<3*Math.PI/2){
this.dx = -this.dx;
}
}
public void draw(){
// 원을 그린다.
Graphics g = canvas.getGraphics();
g.fillOval(this.x, this.y, this.diameter, this.diameter);
g.dispose();
}
public void move(){
// 기존의 원을 없앤다.
Graphics g = this.canvas.getGraphics();
g.setXORMode(this.canvas.getBackground());
g.fillOval(this.x, this.y, this.diameter, this.diameter);
//원의 x, y 좌표를 이동시킨다
this.x += dx;
this.y += dy;
//벽에 부딪히면 입사각에 따라 원을 반사시킨다.
Dimension dimensionOfBox = canvas.getSize();
if(this.x < 0){
dx = -dx;
}
if(this.y < 0){
dy = -dy;
}
if(this.x > dimensionOfBox.width-diameter){
dx = -dx;
}
if(this.y > dimensionOfBox.height-diameter){
dy = -dy;
}
// 다른원과 충돌하면 반지름을 반으로 나누고 둘로 쪼갠다.
for(int i=0; i<BallManager.balls.size(); i++){
Ball targetBall = BallManager.balls.get(i);
if(this.isCollided(targetBall) && i != BallManager.balls.indexOf(this)){
this.splitTwoBall(this, targetBall);
}
}
g.setPaintMode();
g.fillOval(this.x, this.y, this.diameter, this.diameter);
g.dispose();
}
public boolean isCollided(Ball ball){
int distanceX = this.x - ball.x;
int distanceY = this.y - ball.y;
double distance = Math.sqrt((distanceX * distanceX) + (distanceY * distanceY));
//반지름의 합이 중점간의 거리보다 크거나 같으면 둘이 충돌한 것으로 간주한다. 
if(distance <= (this.diameter + ball.diameter)/2){
double distanceXPrime = (this.x + this.dx) - (ball.x + ball.dx);
double distanceYPrime = (this.y + this.dy) - (ball.y + ball.dy);
double distancePrime = Math.sqrt(distanceXPrime * distanceXPrime + distanceYPrime * distanceYPrime);
//반지름의 합이 중점간의 거리보다 크거나 같더라도 처음 생성된 상황은 제외한다.
if(distance > distancePrime){
return true;
}
}
return false;
}
public void split(Ball ball, double rad){
double subtractedRadOfBall = rad - Math.PI/4;
double addedRadOfBall = rad + Math.PI/4;
//반지름이 1보다 크면 기존 원은 사라지고 작은원 둘로 나뉜다.
if(ball.diameter/2>1){
Ball ballOne = new Ball(ball.x, ball.y, ball.diameter/2, subtractedRadOfBall);
Ball ballTwo = new Ball(ball.x, ball.y, ball.diameter/2, addedRadOfBall);
BallManager.balls.add(ballOne);
BallManager.balls.add(ballTwo);
int indexOfBall = BallManager.balls.indexOf(ball); 
ball.isRunnable = false;
BallManager.balls.remove(indexOfBall);
ballOne.start();
ballTwo.start();
}
//반지름이 1보다 작으면 사라진다.
else{
int indexOfBall = BallManager.balls.indexOf(ball);
ball.isRunnable = false;
BallManager.balls.remove(indexOfBall);
}
}
public void splitTwoBall(Ball ballOne, Ball ballTwo){
//ballOne 과 ballTwo의 충돌 이후 진행 방향을 벡터로 계산하였다.
double newRadOfBallOne = (ballOne.diameter/2*Math.sin(ballOne.radian)-ballTwo.y+ballOne.y)/(ballOne.diameter/2*Math.cos(ballOne.radian)-ballTwo.x+ballOne.x);
double newRadOfBallTwo = (ballTwo.diameter/2*Math.sin(ballTwo.radian)-ballOne.y+ballTwo.y)/(ballTwo.diameter/2*Math.cos(ballTwo.radian)-ballOne.x+ballTwo.x);
split(ballOne, newRadOfBallOne);
split(ballTwo, newRadOfBallTwo);
}
public void run(){
this.draw();
while(this.isRunnable){
this.move();
try{ Thread.sleep(20);
}catch(InterruptedException e){}
}
}
}
class BallManager {
public static ArrayList<Ball> balls = new ArrayList<Ball>();
}

벡터 계산해보겠다고 한참 헤멨는데 막상 벡터 계산 하고난 다음에 시간이 훨씬 많이 걸림 ㅋㅋㅋㅋ (..)

잔상이 남는거는 어떻게 해야하는지 모르겠다.
무튼 하.. 

완전 잡탕 코드를 아름답게 만들어준 광록이에게 감사를.. ㅠㅠ


오늘의 교훈 : 큰 문제는 작은 문제로 쪼개서 해결하자.