팩토리 패턴 정의

팩토리 패턴의 핵심 : new 예약어를 패턴에 사용한 서브 클래스나, 인터페이스를 상속한 클래스에게 넘기는 방법이다.

 

1. 팩토리 메서드 패턴

클래스의 인스턴스 생성을 서브 클래스에게 결정시키는 방법이다. (서브클래스를 이용한 방법)

2. 추상 팩토리 패턴 (클래스 다이어그램 까지만 포스팅)

인터페이스를 상속한 클래스에게 인스턴스 생성을 시키는 방법이다. (인터페이스를 이용한 방법)

 

필요한 상황

1. new 예약어를 최대한 인계하는 코드가 필요할 때 -> new 예약어는 변화가 힘든 프로그램을 만들기 때문

switch(instanceName)
{
    case "1":
    return new InstanceOne();

    case "2":
    return new InstanceTwo();
 
    case "3":
    return new InstanceThree();
    
    ...
}

향후 코드 수정이 무조건 필요한 팩토리 함수..

2. 인스턴스 생성 함수가 필요하고, 인스턴스의 종류는 가변인 경우

3. 카테고리화한 비즈니스 모델에 대한 인스턴스 생성을 체계화하고 싶은 경우

Class 다이어그램

1. 팩토리 메서드 패턴

 

 

2. 추상 팩토리 패턴

코드

1. BuisnessModel class

public abstract class BuisnessModel
{
    public string Name { get; set; }
    public int Number { get; set; }
    
    public abstract void doSomething1();
    public abstract void doSomething2();
    
    public override string ToString()
    {
        return $"{Name} : {Number}";
    }
}

2. BuisnessModel class의 sub class들 (팩토리에서 생성할 다양한 모델)

public class FactoryMethodPattern_SubOne_BuisnessOneModel : BuisnessModel
{
    public override void doSomething1()
    {
        Console.WriteLine($"do FactoryMethodPattern_SubOne_BuisnessOneModel job 1");
    }
    
    public override void doSomething2()
    {
        Console.WriteLine($"do FactoryMethodPattern_SubOne_BuisnessOneModel job 2");
    }
}

public class FactoryMethodPattern_SubOne_BuisnessTwoModel : BuisnessModel
{
    public override void doSomething1()
    {
        Console.WriteLine($"do FactoryMethodPattern_SubOne_BuisnessOneModel job 1");
    }
    
    public override void doSomething2()
    {
        Console.WriteLine($"do FactoryMethodPattern_SubOne_BuisnessTwoModel job 2");
    }
}

public class FactoryMethodPattern_SubTwo_BuisnessOneModel : BuisnessModel
{
    public override void doSomething1()
    {
        Console.WriteLine($"do FactoryMethodPattern_SubTwo_BuisnessOneModel job 1");
    }
    
    public override void doSomething2()
    {
        Console.WriteLine($"do FactoryMethodPattern_SubTwo_BuisnessOneModel job 2");
    }
}

public class FactoryMethodPattern_SubTwo_BuisnessTwoModel : BuisnessModel
{
    public override void doSomething1()
    {
        Console.WriteLine($"do FactoryMethodPattern_SubTwo_BuisnessOneModel job 1");
    }
    
    public override void doSomething2()
    {
        Console.WriteLine($"do FactoryMethodPattern_SubTwo_BuisnessTwoModel job 2");
    }
}

3. InstanceStore 추상 Class

public abstract class BaseInstanceStore
{
    public BuisnessModel GetBuisnessModel(string buisness_type)
    {
        BuisnessModel bm = OrderBuisnessModel(buisness_type);
        bm.doSomething1();
        bm.doSomething2();
        return bm;
    }
	
    protected abstract BuisnessModel OrderBuisnessModel(string buisness_type);
}

4. SubInstanceStore Class 들

public class SubOneInstanceStore : BaseInstanceStore
{  
    protected override BuisnessModel OrderBuisnessModel(string buisness_type)
    {
        switch(buisness_type)
        {
            case "ONE":
                return new FactoryMethodPattern_SubOne_BuisnessOneModel() { Name = "FactoryMethodPattern_SubOne_BuisnessOneModel of SubOneInstanceStore", Number = 0 };
            case "TWO":
                return new FactoryMethodPattern_SubOne_BuisnessTwoModel() { Name = "FactoryMethodPattern_SubOne_BuisnessTwoModel of SubOneInstanceStore", Number = 0 };
            default:
                return new FactoryMethodPattern_SubOne_BuisnessOneModel() { Name = "FactoryMethodPattern_SubOne_BuisnessOneModel of SubOneInstanceStore", Number = 0 };
        }
    }
}

public class SubTwoInstanceStore : BaseInstanceStore
{  
    protected override BuisnessModel OrderBuisnessModel(string buisness_type)
    {
        switch(buisness_type)
        {
            case "ONE":
                return new FactoryMethodPattern_SubTwo_BuisnessOneModel() { Name = "FactoryMethodPattern_SubTwo_BuisnessOneModel of SubOneInstanceStore", Number = 0 };
            case "TWO":
                return new FactoryMethodPattern_SubTwo_BuisnessTwoModel() { Name = "FactoryMethodPattern_SubTwo_BuisnessTwoModel of SubOneInstanceStore", Number = 0 };
            default:
                return new FactoryMethodPattern_SubTwo_BuisnessOneModel() { Name = "FactoryMethodPattern_SubTwo_BuisnessOneModel of SubOneInstanceStore", Number = 0 };
        }
    }
}

5. Main 코드

BaseInstanceStore instanceOneFactory = new SubOneInstanceStore();
BuisnessModel bm1 = instanceOneFactory.GetBuisnessModel("ONE");
Console.WriteLine(bm1.ToString());

BaseInstanceStore instanceTwoFactory = new SubTwoInstanceStore();
BuisnessModel bm2 = instanceTwoFactory.GetBuisnessModel("TWO");
Console.WriteLine(bm2.ToString());

코드 설명

1. BuisnessModel Class는 우리가 new 예약어를 통해 실제 인스턴스를 생성할 Class이다. 향후 다양한 파생 클래스의 베이스 클래스로 이용할 것이다. 

2. BuisnessModel class의 sub class들이다. 다양한 모델로 추가 삭제 가능하다.

3. InstanceStore 추상 Class이다. 파생 클래스로 BuisnessModel을 첫 번째로 대분류 한다.

4. InstanceStore의 파생 클래스이다. 파생 클래스로 BuisnessModel을 대분류 하고 파생 클래스의 함수를 통해 소분류로 BuisnessModel을 나눈다.

5. Main 코드는 팩토리 메서드 패턴을 사용하는 방법이다.

 

-- 추상 팩토리 패턴은 생략-- (팩토리 메소드 패턴을 많이 이용하기 때문..) 

설명 보충을 위한 그림 자료

Instance 요청 흐름 (초록선 : 요청 흐름, 보라 : 출력 흐름)

필요에 따라 추가 설명

1. 팩토리 패턴은 우리가 정의한 비즈니스 모델이 많을수록 빛을 발한다.

2. 비즈니스 모델이 추가될 경우 수정해야 하는 부분은 대분류 한 InstanceFactory의 내부 함수이다. 

정리 및 결론

단순 팩토리 함수(switch문으로 만든)와 팩토리 패턴을 비교했을 때 비즈니스 모델의 추가 삭제 요인이 적다면 단순 팩토리 함수가 유용해 보인다. 따라서 우리는 단순 팩토리 함수와 팩토리 패턴을 구분하고 장단점을 따지고 구현할지 말지 판단해야 한다.

코더가 아닌 개발자가 되자!!

'Program > SW Design Patterns' 카테고리의 다른 글

CH6 커맨드 패턴  (0) 2023.03.07
CH5 데코레이터 패턴  (1) 2023.03.05
CH3 옵저버 패턴  (0) 2023.03.03
CH2 싱글턴 패턴  (0) 2023.03.02
CH1 전략 패턴  (0) 2023.03.02

 

옵저버 패턴 정의

제공자 (subject), 구독자 (subscriber)로 구분하여 다룬다. 제공자는 자신의 상태가 변할 경우 자신을 구독한 구독자에게 알리는 역할을 수행한다. 1 대 다 의존성을 가지는 패턴이다.

필요한 상황

1. 제공자의 정보가 변할 때마다 모든 구독자에게 알림을 보내야 하는 경우
2. 구독자의 리소스를 아껴야 할 경우 (제공자에게 데이터를 계속 요청하기보다는 콜백형태로 제공자에게 수동적으로 받기 때문)
3. 구독자 Class와 제공자 Class 간 결합성을 낮추고 싶은 경우

Class 다이어그램

코드

1. ISubject와 IObserver interface 코드

public interface ISubject
{
    void RegistUser(IObserver observer);
    void RemoveUser(IObserver observer);
    void Broadcast();
}

public interface IObserver
{ 
    void update(object sender, EventArgs evetArgs);
}

2. BroacastSubject Class 코드

public class BroadcastSubject : ISubject
{
    private event EventHandler broadcast = null;
    
    public int nCurrentState { get; private set; }
    
    public void Broadcast()
    {
        if (broadcast != null)
        {
            broadcast(this, null);
        }
        else
        {
            Console.WriteLine("no Observer..");
        }
    }
    
    public void ChangeValue(int nInputData)
    {
        nCurrentState = nInputData;
        Console.WriteLine("===========Change Value! Let's Broacast to my Observer!! =============");
        this.Broadcast();
    }
    
    public void RegistUser(IObserver observer)
    {
        broadcast += observer.update;
    }
    
    public void RemoveUser(IObserver observer)
    {
        broadcast -= observer.update;
    }
}

3. Client_User Class 코드

public class Client_User : IObserver
{
    public string strClientUserName = "";
    public Client_User(string strClientUserName, ISubject subject)
    {
        this.strClientUserName = strClientUserName;                
        subject.RegistUser(this);
    }
    
    public void update(object sender, EventArgs eventArgs)
    {
        var broadcaster = sender as BroadcastSubject;
        Console.WriteLine($"=============================================================");
        Console.WriteLine($"{this.strClientUserName} GetData : {broadcaster.nCurrentState}");
    }
}

4. Main 코드

BroadcastSubject broadcastSubject = new BroadcastSubject();
broadcastSubject.ChangeValue(3);

Client_User cu1 = new Client_User("user1", broadcastSubject);
broadcastSubject.ChangeValue(3);

Client_User cu2 = new Client_User("user2", broadcastSubject);
broadcastSubject.ChangeValue(4);

broadcastSubject.RemoveUser(cu2);
broadcastSubject.ChangeValue(5);

코드 설명

1. ISubject, IOversber interface 코드이다. 각 역할별로 필수로 구현해야 하는 함수를 정의했다. 
2. ISubject interface를 적용시킨 BroadcastSubject 코드이다. EventHandler는 C#에서 제공하는 예약어로 해당 EventHandler에 아래와 같이 규격을 맞춘 함수를 등록하면 EventHandler 내부의 invocationlist에 등록되어 해당 EventHandler만 호출하면 등록한 함수를 모두 호출한다. 규격과 이용방법은 아래와 같다.

class TestClass
{
    public event EventHandler broadcast = null;
    
    void broacastToObserver()
    {
        if (broadcast != null)
        {
            broacast(this, null);
        }
    }
}

class ObserverClass()
{
    public void update(object sender, EventArgs eventArgs)
    {
        //do something..
    }
}

TestClass testClass = new TestClass();
ObserverClass obClass = new ObserverClass();

testClass.broacast += obClass.update; //EventHandler에 함수 등록

testClass.broacastToObserver(); //EventHandler 호출!!!!!!!

3. Client_User Class 코드의 특징점은 Observer 입장으로 보자면 생성자에서 Broadcast subject 인스턴스를 참조로 받아와서 자신을 등록하고, 이후 update 함수를 콜백형태로 받는 구조이다.
 

설명 보충을 위한 그림 자료

필요에 따라 추가 설명

1. 옵저버 패턴은 정말 많이 쓰인다. WPF에서도 사용자가 정의한 Class에 대해서 ObservableCollection 등 쓰이는데 이는 모두 GUI 상에 나와있는 버튼으로부터 실시간으로 알림을 받기 위해서다. (사실 정확히 뭐가 Subject이고 Observer 인지는 모른다)
2. 콜백 형태와 매우 유사하다.

정리 및 결론

오늘은 옵저버 패턴을 공부했다. 제법 아는 척하기 좋은 패턴이고 이미 많이 상용화되어 있다. 우리가 직접 이 패턴을 구현해야 할 때는 별로 없을 것 같다. 하지만 이런 패턴으로 구현되어 있는 구조를 본다면 빨리 알아보고 활용할 수 있는 개발자가 되자!!

'Program > SW Design Patterns' 카테고리의 다른 글

CH5 데코레이터 패턴  (1) 2023.03.05
CH4 팩토리 패턴  (0) 2023.03.04
CH2 싱글턴 패턴  (0) 2023.03.02
CH1 전략 패턴  (0) 2023.03.02
개요  (0) 2023.03.01

싱글턴 패턴 정의

하나의 프로그램에서 오직 1개의 인스턴스만을 다루는 패턴이다. 다른 모든 인스턴스에서는 싱글턴 패턴의 인스턴스를 어디서든 끌어와서 쓸 수 있다. 생성자의 접근 권한이 private로 한정되어 있어서 다른 인스턴스에서는 직접적으로 인스턴스를 생성시키지 못한다.

필요한 상황

1. 모든 인스턴스에서 동일한 상태의 인스턴스가 필요한 경우
2. 1개의 인스턴스로 충분한 경우 (일례 : 프로그램 설정정보, 쓰레드 풀)
3. 2개 이상의 인스턴스 생성을 막기 위한 경우

Class 다이어그램

코드

1. Helper Class

public class Helper
{
	static Helper _helperInstance = new Helper();

	private Helper() { }

	static public Helper getInstance()
	{
		return _helperInstance;
	}

	public void UseThis()
	{
		Console.WriteLine("HI I'm singleton instance!");
	}
}

2. main code

Helper.getInstance().UseThis();

 

코드 설명

1. Helpclass
정의한 Class 내부에 static 예약어로 자기 자신의 인스턴스를 할당하였다. 이는 전연변수처럼 프로그램을 시작할때 메모리에 미리 할당하여 사용한다는 의미이다. 그외 특이점은 생성자의 접근 제한자를 private으로 정의하여 자기 자신을 제외하고 생성을 못하게 하였다.
해당 싱글턴 패턴의 인스턴스를 가져오기 위해서는 오직 getInstance 함수를 통해 가져올 수 있다.
 
2. main code
싱글턴 패턴의 인스턴스를 사용하는 방법이다.

설명 보충을 위한 그림 자료

필요에 따라 추가 설명

싱글턴 패턴은 전역 변수와 유사하다. 하지만 몇가지 차이점이 있다.

  차이점 1. 전역 변수는 결국 Class 외부에서 new 예약어를 통해 메모리를 할당하기 때문에 1개 이상의 인스턴스를 생성할 수 있다. 이는 프로그램에 오직 1개의 인스턴스를 생성하려하는 부분을 충족시키지 못한다.
  차이점 2. Class 내부에서 생성을 다루기 때문에 아래 코드와 같이 인스턴스를 사용하기 직전에 생성시키는 방법을 사용할 수 있다.(lazy initialization

public class Helper
{
	static Helper _helperInstance;

	private Helper() { }

    
	static public Helper getInstance()
	{
		lock(typeof(Helper))
		{
			if (_helperInstance == null)
			{
				_helperInstance = new Helper();
			}
		}

		return _helperInstance;
	}

	public void UseThis()
	{
		Console.WriteLine("HI I'm singleton instance!");
	}
}

lock 예약어를 사용하는 이유는 멀티 스레드를 이용할 경우 여러 스레드에서 동시에 생성을 요청할 경우를 막기 위해서 사용하는 것이다.
 

정리 및 결론

1. 싱글턴 패턴은 정말 많이 사용하는 패턴이다.
2. WPF를 사용할때에 MVVM Silverlight 를 사용했었는데 개별 ViewModel의 인스턴스를 관리하는 인스턴스에 사용한 사례를 봤었다. 이처럼 프로그램의 전체를 다루는데(일례 : 서로 다른 ViewModel 간 데이터 교환 등..) 효과적인 패턴이다. 
3. 마지막으로 오늘 탈피한 리챠드 :)

2023년 03월 03일

'Program > SW Design Patterns' 카테고리의 다른 글

CH5 데코레이터 패턴  (1) 2023.03.05
CH4 팩토리 패턴  (0) 2023.03.04
CH3 옵저버 패턴  (0) 2023.03.03
CH1 전략 패턴  (0) 2023.03.02
개요  (0) 2023.03.01

 

전략(Strategy) 패턴 정의

알고리즘 구현 부분을 캡슐화하여 알고리즘의 변경과 수정에 용이한 패턴을 의미한다. 서브 클래스들의 핵심 알고리즘 구현 부분을 별도로 캡슐화하여 베이스 클래스와 서브 클래스 간의 상속으로 인한 결합성을 낮춘다.    

 

핵심 : 베이스 클래스는 핵심 알고리즘의 호출 부분을 인터페이스로 저장하고 호출만수행하고, 핵심 알고리즘의 구현 부분을 캡슐화하여 코딩한다.

필요한 상황

1. 베이스 클래스를 상속 받은 서브 클래스들이 베이스 클래스의 함수를 호출할 때 각기 다른 기능을 수행하는 구조가 필요할 때 (다형성을 이용할 경우)

2. 서브 클래스가 베이스 클래스의 함수를 오버라이딩하여 서브 클래스에서 함수를 재작성 해야하는 경우 (매번 서브 클래스에서 함수를 오버라이딩하여 작성할 경우)

3. 향후 베이스 클래스를 상속받은 서브 클래스가 증가할 것으로 예상 될 경우 (잠재적 기능 추가 요소인 경우)

Class 다이어그램

요구 사항 1. RPG 게임 환경에서 검사, 수도승, 궁사 직업군이 있다.

요구 사항 2. 각 직업군은 서로 다른 공격과 방어 행동을 가진다.

요구 사항 3. 각 직업군은 무기 변경이 가능하다.

코드

 

 

 

1. 사람 Class (베이스 클래스)

public class Human
{
	protected IAttackBehavior attackBehavior { get; set; }
	protected IDefenceBehavior defenceBehavior { get; set; }

	public void Attack()
	{
		attackBehavior.attack();
	}

	public void Defence()
	{
		defenceBehavior.defence();
	}

	public void SetAttackMode(IAttackBehavior ia)
	{
		this.attackBehavior = ia;
	}

	public void SetDefenceMode(IDefenceBehavior id)
	{
		this.defenceBehavior = id;
	}
}

2. 행동 interface 

public interface IDefenceBehavior
{
	void defence();
}
    
public interface IAttackBehavior
{
	void attack();
}

3. 알고리즘 구현 Class 부분 Behavior interface를 상속받음

public class AttackWithBow : IAttackBehavior
{
	public void attack()
	{
		Console.WriteLine("Attack with Bow");
	}
}

public class AttackWithSword : IAttackBehavior
{
	public void attack()
	{
		Console.WriteLine("Attack with Sword");
	}
}

public class AttackWithGlobe : IAttackBehavior
{
	public void attack()
	{
		Console.WriteLine("Attack with Globe");
	}
}

public class DefenceWithBow : IDefenceBehavior
{
	public void defence()
	{
		Console.WriteLine("Defence with Bow");
	}
}

public class DefenceWithSword : IDefenceBehavior
{
	public void defence()
	{
		Console.WriteLine("Defence with Sword");
	}
}

public class DefenceWithGlobe : IDefenceBehavior
{
	public void defence()
	{
		Console.WriteLine("Defence with Globe");
	}
}

4. 전사, 궁사, 수도승 클래스 (서브 클래스)

public class Archer : Human
{
	public Archer()
	{
		this.attackBehavior = new AttackWithBow();
		this.defenceBehavior = new DefenceWithBow();
	}
}

public class SwordMaster : Human
{
	public SwordMaster()
	{
		this.attackBehavior = new AttackWithSword();
		this.defenceBehavior = new DefenceWithSword();
	}
}

public class Monk : Human
{
	public Monk()
	{
		this.attackBehavior = new AttackWithGlobe();
		this.defenceBehavior = new DefenceWithGlobe();
	}
}

5. Main 코드

Attack(new Archer());
Attack(new SwordMaster());
Attack(new Monk());
var instance = new Monk();
instance.SetAttackMode(new AttackWithBow());
Attack(instance);


void Attack(Human human)
{
    human.Attack();
}

void Defence(Human human)
{
    human.Defence();
}

출력 결과

코드 설명

1. 사람 Class (베이스 클래스)

   - 모든 서브 클래스들의 함수와 알고리즘 구현 인터페이스를 담고 있다.

   - Class의 사용자는 서브 클래스들의 특징을 파악할 필요 없고 베이스 클래스의 함수와 특성값만 알면 된다. 

2. 행동 interface

   - 알고리즘 인터페이스이다.

   - 베이스 클래스는 알고리즘 인터페이스 변수를 저장하고, 필요에 따라 인터페이스를 상속받은 다른 구현 알고리즘을 바꿔치기 사용하면 된다.

3. 알고리즘 구현 Class 부분 Behavior interface를 상속받음

   - 알고리즘 인터페이스를 상속받은 Class이다.

   - 실제 알고리즘의 구현이 들어가는 부분이다.

4. 전사, 궁사, 수도승 클래스 (서브 클래스)

   - 생성자 부분에서 행동 interface 규격을 맞추는 Class로 정의하여 베이스 클래스의 행동 interface에 할당하면 된다.

5. Main 코드

   - Main에 정의한 함수는 사람 class의 함수를 호출하지만 각 서브 클래스들로 업캐스팅하여 기입하고 각 서브 클래스들은 각기 다른 행동 interface로 구성했기 때문에 서로 다른 출력 결과를 보여준다.

   - 출력 결과 모든 요구사항을 충족함을 볼 수 있다.

설명 보충을 위한 그림 자료

필요에 따라 추가 설명

1. 베이스 클래스를 상속받아 서브 클래스에서 재사용하는 경우 고려하면 좋다.

2. 상속구조에 의한 베이스 클래스와 서브 클래스 간의 코드 변경에 의한 의존성이 줄어든다.

3. 단 interface라는 추상화 구조가 필요하다.

4. 알고리즘을 사용하는 Class는 interface형 변수를 담고 있다가 필요시 interface에서 정의한 함수를 호출하는 방법이다.

 

정리 및 결론

1. 전략 패턴의 핵심은 베이스 클래스가 특정 interface를 변수로 저장하고 있다가 특정 interface를 상속받은 구현 알고리즘 Class를 변수처럼 사용하는 것

2. 전략 패턴은 서브 클래스에서 베이스 클래스에 구성되어 있는 특정 interface를 원하는 구현 알고리즘으로 할당시킨다.

3. 베이스 클래스를 이용하는 코드(Main 부분)는 베이스 클래스의 함수만 호출해도 다양한 구현 알고리즘을 구성할 수 있다.

4. 객체지향적 사고 팁

    - 변하는 부분은 캡슐화한다. (추가 및 변경이 용이하도록 하는 것)

    - 상속보다는 구성을 이용하면 결합성을 낮출 수 있다. (베이스 클래스가 특정 interface를 변수로 저장하는 것)

    - 직접 구현보다는 interface를 상속받은 구현 Class로 나눠 변수처럼 사용한다.

'Program > SW Design Patterns' 카테고리의 다른 글

CH5 데코레이터 패턴  (1) 2023.03.05
CH4 팩토리 패턴  (0) 2023.03.04
CH3 옵저버 패턴  (0) 2023.03.03
CH2 싱글턴 패턴  (0) 2023.03.02
개요  (0) 2023.03.01

본 카테고리는 SW의 객체지향 접근을 기반으로 하는 SW 디자인 패턴을 다루는 카테고리이다.
주요 목적은 주어지는 사례에 따라 최적의 디자인 패턴을 선택하고 구현까지 할 수 있는 것을 목표로 한다. 
다룰 디자인 패턴과 글의 구성, 개발환경은 아래와 같다.
 

디자인 패턴 목차

1. 전략 패턴
2. 싱글턴 패턴
3. 옵저버 패턴
4. 팩토리 패턴
5. 데코레이터 패턴
6. 커맨드 패턴
7. 어댑터&퍼사드 패턴
8. 스테이트 패턴
9. MVC, MVVM 패턴
 

챕터 구성

1. 패턴 정의
2. 필요한 상황
3. Class 다이어그램
4. 코드
5. 코드 설명
6. 설명 보충을 위한 그림 자료
7. 필요에 따라 추가 설명
8. 정리 및 결론
 

개발 환경

1. Language : C#
2. OS : Windows 11
3. IDE : Visual studio 2019
 

작성 기간

2023-03-02 ~ 2023-03-XX (X일)
 
마지막으로 리챠드 :)

2023년 03월 01일 리챠드

 
 
 
 
 
 

'Program > SW Design Patterns' 카테고리의 다른 글

CH5 데코레이터 패턴  (1) 2023.03.05
CH4 팩토리 패턴  (0) 2023.03.04
CH3 옵저버 패턴  (0) 2023.03.03
CH2 싱글턴 패턴  (0) 2023.03.02
CH1 전략 패턴  (0) 2023.03.02
import math

cumdata = 1
ishere = False

for _ in range(5):
    cumdata *= int(input())
    if math.sqrt(cumdata).is_integer() == True:        
        print('found')
        break
else:
    print('not found')

5개의 값을 입력 받아 차례 대로 곱했을때 제곱수가 있는 경우 found, 없는 경우 not found 를 출력하는 코드이다.

 

보통 flag 라는 변수를 이용해 처리하지만 python의 for-else 문을 이용하여 flag 함수를 제거할 수 있다. 

'Program > Python' 카테고리의 다른 글

가장 많이 나오는 문자열 찾기 (collections의 Counter 함수)  (0) 2022.08.02
itertools의 순열(permutation), 조합(combination)  (0) 2022.08.02
Sinc 함수 구현  (0) 2021.05.06
K번째 큰 수  (0) 2021.05.06
람다 표현식  (0) 2021.04.24
from collections import Counter

my_str = 'dfdefdgf'
data_dict = dict(Counter(sorted(my_str)))

all_values = data_dict.values()
max_value = max(all_values)

answer = ''.join( [key for key in list(data_dict.keys()) if max_value is data_dict[key]] )
print(answer)

collections의 Counter 함수는 list 함수를 입력으로 받아서 dict 형태로 출력을 한다.

이때 key 값을 list의 element 값

value 값은 element의 중복 수 이다.

 

이 특징을 잘 이용하면 직관적으로 풀기 쉽다.

'Program > Python' 카테고리의 다른 글

for-else 문  (0) 2022.08.02
itertools의 순열(permutation), 조합(combination)  (0) 2022.08.02
Sinc 함수 구현  (0) 2021.05.06
K번째 큰 수  (0) 2021.05.06
람다 표현식  (0) 2021.04.24
from itertools import permutations
from itertools import combinations

mylist = [1, 2, 3]

#순열
print(list(permutations(mylist,  len(mylist))))
>> [[1, 2, 3], [1, 3, 2], [2, 1, 3], [2, 3, 1], [3, 1, 2], [3, 2, 1]]

#조합
print(list(combinations(mylist, 2)))
>> [[1,2],[1,3],[2,3]]

 

코딩 테스트를 하다보면 순열, 조합 문제가 나온다. 

예전 C++으로 문제를 풀던 시절에는 재귀함수를 이용해서 풀었겠지만 이렇게 쉽게 구현되어 있다.

 

'Program > Python' 카테고리의 다른 글

for-else 문  (0) 2022.08.02
가장 많이 나오는 문자열 찾기 (collections의 Counter 함수)  (0) 2022.08.02
Sinc 함수 구현  (0) 2021.05.06
K번째 큰 수  (0) 2021.05.06
람다 표현식  (0) 2021.04.24

공부중에 매트랩의 sinc 함수를 찾지 못해서

매트랩은 아니지만 python 전용으로 sinc 함수를 만들어 봤다. 주의할 부분은 sin 함수 안의 매개변수 값의 단위가 degree 인지 radian 인지 명확히 인지 해야 한다. python math의 sin은 radian이다.

즉  3.141592 radian = 180 degree이다.

 

 

sinc 함수 표현 식, https://kr.mathworks.com/

 

 

Code
import math 
import matplotlib.pyplot as plt
import numpy as np

def sinc(x):
    if x == 0:
        return 1
    else:
        return (math.sin(math.pi * x) / (math.pi * x))

x = np.linspace(-5,5,1000)
y = []

for valueX in x:
    y.append(sinc(valueX))


plt.plot(x,y)
plt.show()
결과

 

 

 

첫 줄 입력 자연수 N(3 <=N <=100), 자연수 K (1 <=K <=50)

둘 째줄 입력 자연수 1 ~ 100 사이의 자연수 N개의 배열

 

N개의 배열에서 3개의 값을 조합하여 구할 수 있는 값 중에 K 번째로 큰 값 구하기

주의해야 할 처리 사항 : 중복 숫자 값 입력 가능, K 번째 큰 수에서 중복하는 값은 무시 (ex. [5,5,4,2]에서 2번째로 큰 값은 4)

def find(arraySortedData, index, arraySumData, arrayMaxData,depth):
        
    if depth == 3:
        arrayMaxData.append(arraySumData[0])
        return
    
    for i in range(index, len(arraySortedData)):
        arraySumData[0] += arraySortedData[i]
        find(arraySortedData, i + 1, arraySumData, arrayMaxData, depth + 1)
        arraySumData[0] -= arraySortedData[i]
    

N, K = map(int, input().split())
arrayData = list(map(int,input().split()))
arrayMaxData = []
arraySumData = [0]

find(arrayData, 0, arraySumData, arrayMaxData, 0)

arrayMaxData.sort(reverse=True)

count = 1
preData = arrayMaxData[0]
for i in range(1, len(arrayMaxData)):
    
    if count == K:
        print(preData)
        break
        
    if preData != arrayMaxData[i]:
        count += 1
        preData = arrayMaxData[i]

 

 

후기  

재귀 함수를 이용해서 결과를 구했다. 처음에는 입력 배열 값을 오름차순 정렬하여 재귀 함수를 통해 순회하는 값은 자동으로 오름차순 정렬이 되어있는 배열인 줄 알고 착각을 했다. 하지만 결과는 아니었다. 이 문제 때문에 10분 정도 삽질했다. 추가로 c++에서는  함수에 &예약어를 통해 call by reference를 사용했지만 python은 참조 예약어를 몰라서 배열을 만들어 사용했다.

 

'Program > Python' 카테고리의 다른 글

itertools의 순열(permutation), 조합(combination)  (0) 2022.08.02
Sinc 함수 구현  (0) 2021.05.06
람다 표현식  (0) 2021.04.24
2차원 리스트 다루기  (0) 2021.04.13
List 다루기(2/2)  (0) 2021.03.22

+ Recent posts